@fin.cx/compatibility 4.1.0 → 5.0.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: '4.1.0',
6
+ version: '5.0.0',
7
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)'
8
8
  };
9
9
  //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiMDBfY29tbWl0aW5mb19kYXRhLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vdHMvMDBfY29tbWl0aW5mb19kYXRhLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOztHQUVHO0FBQ0gsTUFBTSxDQUFDLE1BQU0sVUFBVSxHQUFHO0lBQ3hCLElBQUksRUFBRSx1QkFBdUI7SUFDN0IsT0FBTyxFQUFFLE9BQU87SUFDaEIsV0FBVyxFQUFFLCtLQUErSztDQUM3TCxDQUFBIn0=
@@ -1,14 +1,18 @@
1
1
  /**
2
2
  * Why an exchange file could not be written:
3
- * - `invalid_bookings`: a draft the account policy refuses, the message names it; or a general reversal among the
4
- * bookings handed over to a correction Buchungsstapel (a correction file passed as the state handed over);
3
+ * - `invalid_bookings`: a draft the account policy refuses, the message names it; a general reversal among the
4
+ * bookings handed over to a correction Buchungsstapel (a correction file passed as the state handed over); or a row
5
+ * or booking a Buchungsstapel does not hold (no day, an amount that is not positive) or whose Belegdatum lies
6
+ * outside the period of the header, named;
7
+ * - `invalid_header`: a header whose period ends before it begins or does not lie within the one Wirtschaftsjahr
8
+ * beginning on its Wirtschaftsjahr-Beginn;
5
9
  * - `export_failed`: the conversion into rows failed;
6
10
  * - `invalid_documents`: a document of a document-image archive DATEV does not take (its GUID, its format), or none;
7
11
  * - `nothing_to_correct`: a correction Buchungsstapel whose current bookings are the ones handed over;
8
12
  * - `handed_over_cost_centres_unknown`: a correction of a period whose bookings handed over include one whose cost
9
13
  * centres its record does not state (stored before 4.1) and no rows sent were given; the message names it.
10
14
  */
11
- export type TCompatibilityErrorCode = 'invalid_bookings' | 'export_failed' | 'invalid_documents' | 'nothing_to_correct' | 'handed_over_cost_centres_unknown';
15
+ export type TCompatibilityErrorCode = 'invalid_bookings' | 'invalid_header' | 'export_failed' | 'invalid_documents' | 'nothing_to_correct' | 'handed_over_cost_centres_unknown';
12
16
  export declare class CompatibilityError extends Error {
13
17
  readonly code: TCompatibilityErrorCode;
14
18
  constructor(codeArg: TCompatibilityErrorCode, messageArg: string);
package/dist_ts/error.js CHANGED
@@ -5,4 +5,4 @@ export class CompatibilityError extends Error {
5
5
  this.code = codeArg;
6
6
  }
7
7
  }
8
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZXJyb3IuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi90cy9lcnJvci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFZQSxNQUFNLE9BQU8sa0JBQW1CLFNBQVEsS0FBSztJQUczQyxZQUFZLE9BQWdDLEVBQUUsVUFBa0I7UUFDOUQsS0FBSyxDQUFDLFVBQVUsQ0FBQyxDQUFDO1FBQ2xCLElBQUksQ0FBQyxJQUFJLEdBQUcsb0JBQW9CLENBQUM7UUFDakMsSUFBSSxDQUFDLElBQUksR0FBRyxPQUFPLENBQUM7SUFDdEIsQ0FBQztDQUNGIn0=
8
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZXJyb3IuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi90cy9lcnJvci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFnQkEsTUFBTSxPQUFPLGtCQUFtQixTQUFRLEtBQUs7SUFHM0MsWUFBWSxPQUFnQyxFQUFFLFVBQWtCO1FBQzlELEtBQUssQ0FBQyxVQUFVLENBQUMsQ0FBQztRQUNsQixJQUFJLENBQUMsSUFBSSxHQUFHLG9CQUFvQixDQUFDO1FBQ2pDLElBQUksQ0FBQyxJQUFJLEdBQUcsT0FBTyxDQUFDO0lBQ3RCLENBQUM7Q0FDRiJ9
@@ -41,9 +41,12 @@ export declare const bookingsOfRows: (rowsArg: readonly IDatevBuchungsstapelRow[
41
41
  * How many rows two Buchungsstapel of one period do not share, compared on
42
42
  * what a booking says (its day, amount, side, accounts, BU key, Belegfeld 1,
43
43
  * cost centres, and whether it is a general reversal) and not on its wording or its document link. The rows are
44
- * compared as a multiset: a row that stands twice in one and once in the other differs once. A booking stored before
45
- * 4.1, which does not record its cost centres, never differs on them (`pairBookings`); compare `bookingsOfRows` of
46
- * the rows sent for an answer that counts them.
44
+ * compared as a multiset: a row that stands twice in one and once in the other differs once. Both sides are compared
45
+ * as a file states them (`comparableOf`: a `"` as `'`, Belegfeld 1 cut to 36 characters, a character Windows-1252
46
+ * cannot hold as `?`), so bookings stored of rows before writing and bookings read from a file compare alike. A
47
+ * booking stored before 4.1, which does not record its cost centres, never differs on them (`pairBookings`); compare
48
+ * `bookingsOfRows` of the rows sent for an answer that counts them. A booking a Buchungsstapel cannot hold (no day,
49
+ * no positive amount) is refused (`invalid_bookings`).
47
50
  */
48
51
  export declare const differingBookingCount: (leftArg: readonly IExportBooking[], rightArg: readonly IExportBooking[]) => number;
49
52
  /**
@@ -96,11 +99,35 @@ export interface IBuchungsstapelFile {
96
99
  csv: string;
97
100
  /** the file in Windows-1252, as it is handed over */
98
101
  bytes: Uint8Array;
102
+ /** the rows as they were given to the writer; the file states them as `rowsAsWritten` does */
99
103
  rows: IDatevBuchungsstapelRow[];
104
+ /**
105
+ * The bookings the file states, read back from its bytes (`@fin.cx/skr` `readExtfBuchungsstapel`): a `"` in a
106
+ * text field as `'`, Belegfeld 1 cut to 36 characters, a character Windows-1252 cannot hold as `?`. What a file
107
+ * read back is compared with, and what a correction's `handedOver` is (4.1 and before: the rows' bookings before
108
+ * writing).
109
+ */
100
110
  bookings: IExportBooking[];
101
111
  /** the characters Windows-1252 cannot write, each written as `?`, with the row and field it stands in */
102
112
  replacedCharacters: IBuchungsstapelReplacement[];
103
113
  }
114
+ /**
115
+ * Rows as a Buchungsstapel file states them: each row written by the writer (`@fin.cx/skr` `writeExtfBuchungsstapel`,
116
+ * which writes a `"` in a text field as `'` and cuts a field to its DATEV length), encoded in Windows-1252 (a
117
+ * character it cannot hold written `?`, `encodeWindows1252`), and read back (`@fin.cx/skr` `readExtfBuchungsstapel`),
118
+ * in the order given. Every rule of the writer, the encoding and the reader applies because the rows go through them,
119
+ * not through a copy of their rules. The rows of each calendar year are written as one file whose header spans their
120
+ * days; the header states nothing a row is read by beyond its days. A row the writer or the reader refuses throws as
121
+ * it does.
122
+ */
123
+ export declare const rowsAsWritten: (rowsArg: readonly IDatevBuchungsstapelRow[]) => IDatevBuchungsstapelRow[];
124
+ /**
125
+ * The bookings of rows as a Buchungsstapel file states them (`rowsAsWritten`): what a file handed over, read back
126
+ * with `readExtfBuchungsstapel`, is compared with. `bookingsOfRows` of the rows before writing keeps what the file
127
+ * does not (a `"` in Belegfeld 1, a Belegfeld 1 longer than its 36 characters, a character Windows-1252 cannot
128
+ * hold), and Belegfeld 1 is compared, so such a booking would differ from the file forever.
129
+ */
130
+ export declare const bookingsAsWritten: (rowsArg: readonly IDatevBuchungsstapelRow[]) => IExportBooking[];
104
131
  /** Writes a Buchungsstapel: the rows of the drafts, the header and the caption row, encoded in Windows-1252. */
105
132
  export declare const writeBuchungsstapel: (optionsArg: IBuchungsstapelOptions) => IBuchungsstapelFile;
106
133
  /**
@@ -113,8 +140,10 @@ export declare const rowOfBooking: (bookingArg: IExportBooking) => IDatevBuchung
113
140
  * handed over that the current ones no longer hold (`reversed`, each once for each time it is missing), the ones they
114
141
  * still hold (`kept`, as they were handed over) and the current rows the bookings handed over do not hold (`added`),
115
142
  * each in its order. A booking that stands in both is kept: a changed text or document link is no changed booking,
116
- * a changed cost centre is. A booking handed over whose cost centres its record does not state (stored before 4.1)
117
- * is refused (`handed_over_cost_centres_unknown`): pass `bookingsOfRows` of the rows sent instead.
143
+ * a changed cost centre is. The current rows are compared as a file states them (`bookingsAsWritten`), as the
144
+ * bookings handed over are; `added` are the rows themselves, which the writer writes. A booking handed over whose
145
+ * cost centres its record does not state (stored before 4.1) is refused (`handed_over_cost_centres_unknown`): pass
146
+ * `bookingsOfRows` of the rows sent instead.
118
147
  */
119
148
  export declare const correctionOf: (handedOverArg: readonly IExportBooking[], currentArg: readonly IDatevBuchungsstapelRow[]) => {
120
149
  reversed: IExportBooking[];
@@ -131,14 +160,16 @@ export interface ICorrectionBuchungsstapelOptions {
131
160
  * The bookings of the period as they were handed over, as a whole: the bookings of its Buchungsstapel as stored
132
161
  * (`IBuchungsstapelFile.bookings`), or after a correction the period's bookings as that correction left them
133
162
  * (`bookingsAfter`). Each must state its cost centres: one stored before 4.1 does not, and is refused
134
- * (`handed_over_cost_centres_unknown`); pass the rows sent for it.
163
+ * (`handed_over_cost_centres_unknown`); pass the rows sent for it. Bookings stored by any version, before or after
164
+ * writing, are compared as a file states them (`comparableOf`), so a reference the writer changed is no change.
135
165
  */
136
166
  handedOver?: readonly IExportBooking[];
137
167
  /**
138
168
  * The rows of the Buchungsstapel as it was sent: the transmitted file read back (`@fin.cx/skr`
139
- * `readExtfBuchungsstapel(bytes).rows`, skr 6.1.0 and later) or the rows written (`IBuchungsstapelFile.rows`). What
140
- * DATEV received, cost centres (fields 37 and 38) included, so a reversal mirrors it exactly. For a Stapel whose
141
- * bookings were stored before 4.1.
169
+ * `readExtfBuchungsstapel(bytes).rows`, skr 7.0.1 and later) or the rows given to the writer
170
+ * (`IBuchungsstapelFile.rows`), taken as the file states them (`bookingsAsWritten`). What DATEV received, cost
171
+ * centres (fields 37 and 38) included, so a reversal mirrors it exactly. For a Stapel whose bookings were stored
172
+ * before 4.1, which record no cost centres.
142
173
  */
143
174
  handedOverRows?: readonly IDatevBuchungsstapelRow[];
144
175
  /** the period's drafts as they stand now */
@@ -97,16 +97,32 @@ const pairBookings = (leftArg, rightArg) => {
97
97
  pairLeft(false);
98
98
  return { leftPaired, rightPaired };
99
99
  };
100
+ /**
101
+ * Bookings as a Buchungsstapel file states them, for comparing: each written as the row it was written as
102
+ * (`rowOfBooking`) and read back (`bookingsAsWritten`), so bookings stored of rows before writing (4.1 and before)
103
+ * and bookings read from a file compare alike. One that records no cost centres (stored before 4.1) keeps recording
104
+ * none, so it still never differs on them. A booking a Buchungsstapel cannot hold is refused (`invalid_bookings`).
105
+ */
106
+ const comparableOf = (bookingsArg) => bookingsAsWritten(bookingsArg.map((bookingArg) => rowOfBooking(bookingArg))).map((bookingArg, indexArg) => {
107
+ if (recordsCostCentres(bookingsArg[indexArg])) {
108
+ return bookingArg;
109
+ }
110
+ const { kost1: _kost1, kost2: _kost2, ...unrecorded } = bookingArg;
111
+ return unrecorded;
112
+ });
100
113
  /**
101
114
  * How many rows two Buchungsstapel of one period do not share, compared on
102
115
  * what a booking says (its day, amount, side, accounts, BU key, Belegfeld 1,
103
116
  * cost centres, and whether it is a general reversal) and not on its wording or its document link. The rows are
104
- * compared as a multiset: a row that stands twice in one and once in the other differs once. A booking stored before
105
- * 4.1, which does not record its cost centres, never differs on them (`pairBookings`); compare `bookingsOfRows` of
106
- * the rows sent for an answer that counts them.
117
+ * compared as a multiset: a row that stands twice in one and once in the other differs once. Both sides are compared
118
+ * as a file states them (`comparableOf`: a `"` as `'`, Belegfeld 1 cut to 36 characters, a character Windows-1252
119
+ * cannot hold as `?`), so bookings stored of rows before writing and bookings read from a file compare alike. A
120
+ * booking stored before 4.1, which does not record its cost centres, never differs on them (`pairBookings`); compare
121
+ * `bookingsOfRows` of the rows sent for an answer that counts them. A booking a Buchungsstapel cannot hold (no day,
122
+ * no positive amount) is refused (`invalid_bookings`).
107
123
  */
108
124
  export const differingBookingCount = (leftArg, rightArg) => {
109
- const { leftPaired, rightPaired } = pairBookings(leftArg, rightArg);
125
+ const { leftPaired, rightPaired } = pairBookings(comparableOf(leftArg), comparableOf(rightArg));
110
126
  return [...leftPaired, ...rightPaired].filter((pairedArg) => !pairedArg).length;
111
127
  };
112
128
  /**
@@ -172,6 +188,8 @@ export const replacedCharactersOfRows = (rowsArg) => {
172
188
  };
173
189
  /** The file of rows: the header and the caption row, the rows, encoded in Windows-1252, with where each character stands. */
174
190
  const fileOfRows = (rows, headerArg, filenameArg) => {
191
+ refuseUnwritableRows(rows);
192
+ refuseOutsideHeader(rows, headerArg);
175
193
  const { csv } = plugins.skrCore.writeExtfBuchungsstapel(rows, headerArg);
176
194
  const { bytes, replaced } = encodeWindows1252(csv);
177
195
  // the file is the header line, the caption line and one line per row, each ending in CRLF (`writeExtfBuchungsstapel`)
@@ -197,8 +215,118 @@ const fileOfRows = (rows, headerArg, filenameArg) => {
197
215
  }
198
216
  return { ...replacedArg, row, field: fieldAt(fieldStartsOf(rowLines[row]), replacedArg.offset - lineStarts[row]) };
199
217
  });
200
- return { filename: filenameArg, csv, bytes, rows, bookings: bookingsOfRows(rows), replacedCharacters };
218
+ // the bookings of what was written, as the file states them
219
+ const written = plugins.skrCore.readExtfBuchungsstapel(bytes).rows;
220
+ if (written.length !== rows.length) {
221
+ throw new CompatibilityError('export_failed', `${rows.length} row(s) written, ${written.length} read back`);
222
+ }
223
+ return { filename: filenameArg, csv, bytes, rows, bookings: bookingsOfRows(written), replacedCharacters };
224
+ };
225
+ /** The Belegdatum of a row as its day, midnight UTC, in epoch milliseconds. */
226
+ const dayOfRow = (rowArg) => Date.UTC(rowArg.belegDatum.getUTCFullYear(), rowArg.belegDatum.getUTCMonth(), rowArg.belegDatum.getUTCDate());
227
+ /** A row as a refusal names it: its place among the rows given, its day, amount, side, accounts and Belegfeld 1. */
228
+ const rowNameOf = (rowArg, indexArg) => `row ${indexArg + 1} (${Number.isNaN(rowArg.belegDatum.getTime()) ? 'no day' : rowArg.belegDatum.toISOString().slice(0, 10)}, ${rowArg.umsatzCents} ${rowArg.sollHaben} ${rowArg.konto}/${rowArg.gegenKonto}`
229
+ + `${rowArg.belegfeld1 ? `, Belegfeld 1 ${rowArg.belegfeld1}` : ''})`;
230
+ /**
231
+ * Refuses a row a Buchungsstapel does not hold, before anything is written: a Belegdatum that is no day, and an
232
+ * amount that is not a positive whole number of cents (a Buchungsstapel states the side apart, field 2, and
233
+ * `readExtfBuchungsstapel` refuses any other). `invalid_bookings`, naming the row.
234
+ */
235
+ const refuseUnwritableRows = (rowsArg) => {
236
+ rowsArg.forEach((rowArg, indexArg) => {
237
+ if (Number.isNaN(rowArg.belegDatum.getTime())) {
238
+ throw new CompatibilityError('invalid_bookings', `${rowNameOf(rowArg, indexArg)} has no Belegdatum`);
239
+ }
240
+ if (!Number.isSafeInteger(rowArg.umsatzCents) || rowArg.umsatzCents <= 0) {
241
+ throw new CompatibilityError('invalid_bookings', `${rowNameOf(rowArg, indexArg)}: a Buchungsstapel states a positive amount, the side apart`);
242
+ }
243
+ });
201
244
  };
245
+ /**
246
+ * Refuses a header whose period a Buchungsstapel cannot state (`invalid_header`): Datum von after Datum bis, or a
247
+ * period that does not lie within the one Wirtschaftsjahr beginning on the Wirtschaftsjahr-Beginn (a Belegdatum is
248
+ * written TTMM, and the reader takes its year from them); and every row whose Belegdatum lies outside the period
249
+ * (`invalid_bookings`, naming it). Checked before anything is written.
250
+ */
251
+ const refuseOutsideHeader = (rowsArg, headerArg) => {
252
+ const day = (dateArg) => Date.UTC(dateArg.getUTCFullYear(), dateArg.getUTCMonth(), dateArg.getUTCDate());
253
+ const from = day(headerArg.dateFrom);
254
+ const to = day(headerArg.dateTo);
255
+ const start = day(headerArg.fiscalYearStart);
256
+ const end = Date.UTC(headerArg.fiscalYearStart.getUTCFullYear() + 1, headerArg.fiscalYearStart.getUTCMonth(), headerArg.fiscalYearStart.getUTCDate());
257
+ const iso = (timeArg) => new Date(timeArg).toISOString().slice(0, 10);
258
+ if ([from, to, start].some(Number.isNaN)) {
259
+ throw new CompatibilityError('invalid_header', 'the header states no day for the Wirtschaftsjahr-Beginn, Datum von or Datum bis');
260
+ }
261
+ if (to < from) {
262
+ throw new CompatibilityError('invalid_header', `the period of the header ends (${iso(to)}) before it begins (${iso(from)})`);
263
+ }
264
+ if (from < start || to >= end) {
265
+ throw new CompatibilityError('invalid_header', `the period of the header, ${iso(from)} to ${iso(to)}, does not lie within the Wirtschaftsjahr beginning ${iso(start)}`);
266
+ }
267
+ rowsArg.forEach((rowArg, indexArg) => {
268
+ const time = dayOfRow(rowArg);
269
+ if (time < from || time > to) {
270
+ throw new CompatibilityError('invalid_bookings', `${rowNameOf(rowArg, indexArg)} lies outside the period of the header, ${iso(from)} to ${iso(to)}`);
271
+ }
272
+ });
273
+ };
274
+ /**
275
+ * Rows as a Buchungsstapel file states them: each row written by the writer (`@fin.cx/skr` `writeExtfBuchungsstapel`,
276
+ * which writes a `"` in a text field as `'` and cuts a field to its DATEV length), encoded in Windows-1252 (a
277
+ * character it cannot hold written `?`, `encodeWindows1252`), and read back (`@fin.cx/skr` `readExtfBuchungsstapel`),
278
+ * in the order given. Every rule of the writer, the encoding and the reader applies because the rows go through them,
279
+ * not through a copy of their rules. The rows of each calendar year are written as one file whose header spans their
280
+ * days; the header states nothing a row is read by beyond its days. A row the writer or the reader refuses throws as
281
+ * it does.
282
+ */
283
+ export const rowsAsWritten = (rowsArg) => {
284
+ refuseUnwritableRows(rowsArg);
285
+ const written = new Array(rowsArg.length);
286
+ // the indexes of the rows of each calendar year, and the first and last day among them
287
+ const years = new Map();
288
+ rowsArg.forEach((rowArg, indexArg) => {
289
+ const year = rowArg.belegDatum.getUTCFullYear();
290
+ const time = dayOfRow(rowArg);
291
+ const group = years.get(year);
292
+ if (group) {
293
+ group.indexes.push(indexArg);
294
+ group.first = Math.min(group.first, time);
295
+ group.last = Math.max(group.last, time);
296
+ }
297
+ else {
298
+ years.set(year, { indexes: [indexArg], first: time, last: time });
299
+ }
300
+ });
301
+ for (const [year, group] of years) {
302
+ const { csv } = plugins.skrCore.writeExtfBuchungsstapel(group.indexes.map((indexArg) => rowsArg[indexArg]), {
303
+ createdAt: new Date(Date.UTC(year, 0, 1)),
304
+ consultantNumber: 0,
305
+ clientNumber: 0,
306
+ // a Belegdatum is written TTMM: the reader takes its year from the Wirtschaftsjahr and the period of the header
307
+ fiscalYearStart: new Date(Date.UTC(year, 0, 1)),
308
+ dateFrom: new Date(group.first),
309
+ dateTo: new Date(group.last),
310
+ label: '',
311
+ festschreibung: false,
312
+ });
313
+ const read = plugins.skrCore.readExtfBuchungsstapel(encodeWindows1252(csv).bytes).rows;
314
+ if (read.length !== group.indexes.length) {
315
+ throw new CompatibilityError('export_failed', `${group.indexes.length} row(s) written, ${read.length} read back`);
316
+ }
317
+ group.indexes.forEach((indexArg, positionArg) => {
318
+ written[indexArg] = read[positionArg];
319
+ });
320
+ }
321
+ return written;
322
+ };
323
+ /**
324
+ * The bookings of rows as a Buchungsstapel file states them (`rowsAsWritten`): what a file handed over, read back
325
+ * with `readExtfBuchungsstapel`, is compared with. `bookingsOfRows` of the rows before writing keeps what the file
326
+ * does not (a `"` in Belegfeld 1, a Belegfeld 1 longer than its 36 characters, a character Windows-1252 cannot
327
+ * hold), and Belegfeld 1 is compared, so such a booking would differ from the file forever.
328
+ */
329
+ export const bookingsAsWritten = (rowsArg) => bookingsOfRows(rowsAsWritten(rowsArg));
202
330
  /** Writes a Buchungsstapel: the rows of the drafts, the header and the caption row, encoded in Windows-1252. */
203
331
  export const writeBuchungsstapel = (optionsArg) => fileOfRows(datevRowsOf(optionsArg.drafts, optionsArg.policy), optionsArg.header, optionsArg.filename);
204
332
  /**
@@ -241,12 +369,15 @@ const refuseCostCentresUnknown = (handedOverArg) => {
241
369
  * handed over that the current ones no longer hold (`reversed`, each once for each time it is missing), the ones they
242
370
  * still hold (`kept`, as they were handed over) and the current rows the bookings handed over do not hold (`added`),
243
371
  * each in its order. A booking that stands in both is kept: a changed text or document link is no changed booking,
244
- * a changed cost centre is. A booking handed over whose cost centres its record does not state (stored before 4.1)
245
- * is refused (`handed_over_cost_centres_unknown`): pass `bookingsOfRows` of the rows sent instead.
372
+ * a changed cost centre is. The current rows are compared as a file states them (`bookingsAsWritten`), as the
373
+ * bookings handed over are; `added` are the rows themselves, which the writer writes. A booking handed over whose
374
+ * cost centres its record does not state (stored before 4.1) is refused (`handed_over_cost_centres_unknown`): pass
375
+ * `bookingsOfRows` of the rows sent instead.
246
376
  */
247
377
  export const correctionOf = (handedOverArg, currentArg) => {
248
378
  refuseCostCentresUnknown(handedOverArg);
249
- const { leftPaired, rightPaired } = pairBookings(handedOverArg, bookingsOfRows(currentArg));
379
+ // the current rows as a file states them, as the state handed over was: a reference the writer changes is the same
380
+ const { leftPaired, rightPaired } = pairBookings(comparableOf(handedOverArg), bookingsAsWritten(currentArg));
250
381
  return {
251
382
  reversed: handedOverArg.filter((_bookingArg, indexArg) => !leftPaired[indexArg]),
252
383
  kept: handedOverArg.filter((_bookingArg, indexArg) => leftPaired[indexArg]),
@@ -263,7 +394,8 @@ export const correctionOf = (handedOverArg, currentArg) => {
263
394
  * twice or not at all; `handed_over_cost_centres_unknown` for a booking whose cost centres are not known.
264
395
  */
265
396
  export const writeCorrectionBuchungsstapel = (optionsArg) => {
266
- const handedOver = optionsArg.handedOverRows !== undefined ? bookingsOfRows(optionsArg.handedOverRows) : optionsArg.handedOver;
397
+ // rows read back from the file sent are as written already; rows given to the writer become what it wrote
398
+ const handedOver = optionsArg.handedOverRows !== undefined ? bookingsAsWritten(optionsArg.handedOverRows) : optionsArg.handedOver;
267
399
  if (handedOver === undefined || (optionsArg.handedOver !== undefined && optionsArg.handedOverRows !== undefined)) {
268
400
  throw new CompatibilityError('invalid_bookings', 'pass the state handed over once: the bookings stored (handedOver) or the rows sent (handedOverRows)');
269
401
  }
@@ -277,6 +409,8 @@ export const writeCorrectionBuchungsstapel = (optionsArg) => {
277
409
  throw new CompatibilityError('nothing_to_correct', 'the bookings of the period are the ones handed over; there is nothing to correct');
278
410
  }
279
411
  const rows = [...reversed.map((bookingArg) => ({ ...rowOfBooking(bookingArg), generalumkehr: true })), ...added];
280
- return { ...fileOfRows(rows, optionsArg.header, optionsArg.filename), reversed, added, bookingsAfter: [...kept, ...bookingsOfRows(added)] };
412
+ const file = fileOfRows(rows, optionsArg.header, optionsArg.filename);
413
+ // the rows booked anew as the correction file states them, after the reversals
414
+ return { ...file, reversed, added, bookingsAfter: [...kept, ...file.bookings.slice(reversed.length)] };
281
415
  };
282
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi90cy9leHRmL2luZGV4LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sS0FBSyxPQUFPLE1BQU0sY0FBYyxDQUFDO0FBQ3hDLE9BQU8sRUFBRSxrQkFBa0IsRUFBRSxNQUFNLGFBQWEsQ0FBQztBQUNqRCxPQUFPLEVBQUUsaUJBQWlCLEVBQTJCLE1BQU0sc0JBQXNCLENBQUM7QUFFbEYsT0FBTyxFQUFFLGtCQUFrQixFQUFnQyxNQUFNLGFBQWEsQ0FBQztBQUsvRSxzRkFBc0Y7QUFDdEYsTUFBTSxDQUFDLE1BQU0saUJBQWlCLEdBQUcsZ0NBQWdDLENBQUM7QUFFbEUsd0ZBQXdGO0FBQ3hGLE1BQU0sQ0FBQyxNQUFNLFlBQVksR0FBRyxDQUFDLFFBQWdCLEVBQVUsRUFBRSxDQUFDLHVCQUF1QixRQUFRLE1BQU0sQ0FBQztBQStCaEcsMEVBQTBFO0FBQzFFLE1BQU0sVUFBVSxHQUFHLENBQUMsT0FBZSxFQUFVLEVBQUUsQ0FBQyxPQUFPLENBQUMsT0FBTyxDQUFDLFlBQVksRUFBRSxFQUFFLENBQUMsQ0FBQyxPQUFPLENBQUMsV0FBVyxFQUFFLEVBQUUsQ0FBQyxDQUFDLElBQUksRUFBRSxDQUFDO0FBRWxILDRDQUE0QztBQUM1QyxNQUFNLENBQUMsTUFBTSxjQUFjLEdBQUcsQ0FBQyxPQUEyQyxFQUFvQixFQUFFLENBQzlGLE9BQU8sQ0FBQyxHQUFHLENBQUMsQ0FBQyxNQUFNLEVBQUUsRUFBRSxDQUFDLENBQUM7SUFDdkIsV0FBVyxFQUFFLE1BQU0sQ0FBQyxXQUFXO0lBQy9CLFNBQVMsRUFBRSxNQUFNLENBQUMsU0FBUztJQUMzQixLQUFLLEVBQUUsTUFBTSxDQUFDLEtBQUs7SUFDbkIsVUFBVSxFQUFFLE1BQU0sQ0FBQyxVQUFVO0lBQzdCLEtBQUssRUFBRSxNQUFNLENBQUMsWUFBWTtJQUMxQixJQUFJLEVBQUUsTUFBTSxDQUFDLFVBQVUsQ0FBQyxXQUFXLEVB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
416
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi90cy9leHRmL2luZGV4LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sS0FBSyxPQUFPLE1BQU0sY0FBYyxDQUFDO0FBQ3hDLE9BQU8sRUFBRSxrQkFBa0IsRUFBRSxNQUFNLGFBQWEsQ0FBQztBQUNqRCxPQUFPLEVBQUUsaUJBQWlCLEVBQTJCLE1BQU0sc0JBQXNCLENBQUM7QUFFbEYsT0FBTyxFQUFFLGtCQUFrQixFQUFnQyxNQUFNLGFBQWEsQ0FBQztBQUsvRSxzRkFBc0Y7QUFDdEYsTUFBTSxDQUFDLE1BQU0saUJBQWlCLEdBQUcsZ0NBQWdDLENBQUM7QUFFbEUsd0ZBQXdGO0FBQ3hGLE1BQU0sQ0FBQyxNQUFNLFlBQVksR0FBRyxDQUFDLFFBQWdCLEVBQVUsRUFBRSxDQUFDLHVCQUF1QixRQUFRLE1BQU0sQ0FBQztBQStCaEcsMEVBQTBFO0FBQzFFLE1BQU0sVUFBVSxHQUFHLENBQUMsT0FBZSxFQUFVLEVBQUUsQ0FBQyxPQUFPLENBQUMsT0FBTyxDQUFDLFlBQVksRUFBRSxFQUFFLENBQUMsQ0FBQyxPQUFPLENBQUMsV0FBVyxFQUFFLEVBQUUsQ0FBQyxDQUFDLElBQUksRUFBRSxDQUFDO0FBRWxILDRDQUE0QztBQUM1QyxNQUFNLENBQUMsTUFBTSxjQUFjLEdBQUcsQ0FBQyxPQUEyQyxFQUFvQixFQUFFLENBQzlGLE9BQU8sQ0FBQyxHQUFHLENBQUMsQ0FBQyxNQUFNLEVBQUUsRUFBRSxDQUFDLENBQUM7SUFDdkIsV0FBVyxFQUFFLE1BQU0sQ0FBQyxXQUFXO0lBQy9CLFNBQVMsRUFBRSxNQUFNLENBQUMsU0FBUztJQUMzQixLQUFLLEVBQUUsTUFBTSxDQUFDLEtBQUs7SUFDbkIsVUFBVSxFQUFFLE1BQU0sQ0FBQyxVQUFVO0lBQzdCLEtBQUssRUFBRSxNQUFNLENBQUMsWUFBWTtJQUMxQixJQUFJLEVBQUUsTUFBTSxDQUFDLFVBQVUsQ0FBQyxXQUFXLEVB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
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fin.cx/compatibility",
3
- "version": "4.1.0",
3
+ "version": "5.0.0",
4
4
  "private": false,
5
5
  "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
6
  "main": "dist_ts/index.js",
@@ -45,7 +45,7 @@
45
45
  "@push.rocks/smartarchive": "^5.4.1"
46
46
  },
47
47
  "devDependencies": {
48
- "@fin.cx/skr": "^6.0.0",
48
+ "@fin.cx/skr": "^7.0.1",
49
49
  "@git.zone/tsbuild": "^5.0.0",
50
50
  "@git.zone/tsrun": "^3.0.2",
51
51
  "@git.zone/tstest": "^6.3.2",
@@ -58,7 +58,7 @@
58
58
  "license.md"
59
59
  ],
60
60
  "peerDependencies": {
61
- "@fin.cx/skr": "^6.0.0"
61
+ "@fin.cx/skr": "^7.0.1"
62
62
  },
63
63
  "scripts": {
64
64
  "test": "(tstest test/ --verbose)",
package/readme.md CHANGED
@@ -17,7 +17,7 @@ For reporting bugs, issues, or security vulnerabilities, please visit [community
17
17
  pnpm install @fin.cx/compatibility @fin.cx/skr
18
18
  ```
19
19
 
20
- `@fin.cx/skr` (^6.0.0) is a peer dependency: the drafts and the account policy the EXTF writer takes are built by your copy of skr, and the writer turns them into rows with the same copy, so the rows follow the chart the drafts were booked on (which accounts are Automatikkonten, which carry VAT). A second copy of skr of another major would write rows by another chart; a package manager that finds your skr outside the range says so as an unmet peer.
20
+ `@fin.cx/skr` (^7.0.1) is a peer dependency: the drafts and the account policy the EXTF writer takes are built by your copy of skr, and the writer turns them into rows with the same copy, so the rows follow the chart the drafts were booked on (which accounts are Automatikkonten, which carry VAT). A second copy of skr of another major would write rows by another chart; a package manager that finds your skr outside the range says so as an unmet peer.
21
21
 
22
22
  ## Usage
23
23
 
@@ -42,7 +42,7 @@ const file = extf.writeBuchungsstapel({
42
42
  filename: extf.extfFilename('2026-03'), // EXTF_Buchungsstapel_2026-03.csv
43
43
  });
44
44
  file.bytes; // Uint8Array in Windows-1252, served as extf.EXTF_CONTENT_TYPE
45
- file.bookings; // what each row says, for keeping and comparing
45
+ file.bookings; // what each row says as the file states it, for keeping and comparing
46
46
  file.replacedCharacters; // [{ offset, character: 'ő', row: 1, field: 14 }, …]: written as "?"
47
47
  ```
48
48
 
@@ -50,11 +50,14 @@ file.replacedCharacters; // [{ offset, character: 'ő', row: 1, field: 14 }, …
50
50
  - **The same without a file.** `extf.replacedCharactersOfRows(rows)` names the characters of each row the file could not hold (`{ row, field, character }`), without a header and without writing anything: for a preview, before the consultant and client numbers of the header are known. It reads each row's line as the writer writes it (`@fin.cx/skr` `datevRowFields`), so a character a field is cut off before (the Buchungstext keeps 60 characters) is not named.
51
51
 
52
52
  - **A draft the account policy refuses** throws `CompatibilityError` with code `invalid_bookings` and a message naming the draft.
53
+ - **What the reader would refuse is refused before writing.** A header whose period ends before it begins or leaves the Wirtschaftsjahr beginning on its Wirtschaftsjahr-Beginn throws code `invalid_header`; a row whose Belegdatum lies outside that period, is no day, or whose amount is not positive throws `invalid_bookings`, naming the row.
53
54
  - **A failed conversion** throws code `export_failed`.
54
55
  - **A document-image archive DATEV would not take** (no document, a GUID of another form, a format it does not take) throws code `invalid_documents`.
55
56
  - **`differingBookingCount(left, right)`** counts the rows two Stapel of one period do not share. It compares each booking's day, amount, side, accounts, BU key, Belegfeld 1, cost centres (KOST1, KOST2) and whether it is a general reversal, as a multiset, and ignores wording and document links. A booking stored before 4.1 has no cost-centre fields: its record says nothing of them, and they never make it differ; compare `bookingsOfRows` of the rows sent for an answer that counts them.
56
- - **A correction of a period handed over.** `writeCorrectionBuchungsstapel({ handedOver, drafts, policy, header, filename })` writes only what changed since the state handed over: each booking handed over that the drafts no longer hold is written again with field 118 "Generalumkehr" set, so DATEV takes it back on its own side and day, then each row of the drafts that was not handed over; what stands in both is not written. A changed text or document link is no change; a changed cost centre is, so the booking is taken back on the cost centre DATEV received and booked on the new one. Every row keeps its Belegdatum, so it counts in the period it belongs to; a booking handed over is never replaced (§ 146 Abs. 4 AO), which also holds once DATEV has fixed the period (Festschreibung). The file names what it takes back (`reversed`), what it books (`added`) and the bookings after it (`bookingsAfter`: each booking it keeps as it was handed over, text and document link included, then the new rows). `correctionOf(handedOver, rows)` gives `reversed`, `kept` and `added` without a file, and `rowOfBooking(booking)` the row a booking was written as.
57
- - **The state handed over** is given once: the bookings stored of it (`handedOver`: the bookings of its Buchungsstapel as 4.1 records them, or the last correction's `bookingsAfter`), or the rows of the Stapel as it was sent (`handedOverRows`: the transmitted file read back with `@fin.cx/skr` `readExtfBuchungsstapel(bytes).rows`, skr 6.1.0 and later, or the `rows` of the file written). A booking stored before 4.1 has no cost-centre fields, although the Stapel sent stated them (fields 37 and 38): a correction refuses it with code `handed_over_cost_centres_unknown`, naming it, since whether it must be taken back turns on the cost centres DATEV holds and a reversal without them would not mirror it; pass `handedOverRows` for such a period. Nothing changed is refused with `nothing_to_correct`; a general reversal in the state handed over (a correction file passed as the state), or a state given twice or not at all, with `invalid_bookings`.
57
+ - **The bookings as the file states them.** `extf.bookingsAsWritten(rows)` (and `extf.rowsAsWritten(rows)`) writes the rows with skr's writer, encodes them in Windows-1252 and reads them back with skr's reader: a `"` in a text field becomes `'`, Belegfeld 1 is cut to 36 characters, a line break becomes a space and a character Windows-1252 cannot hold becomes `?`, as in the file. `writeBuchungsstapel`'s `bookings` are read back from the bytes it wrote. `differingBookingCount` and a correction take both sides as a file states them, so bookings stored before writing (4.1 and before), bookings of this version and rows read back from the file sent compare alike; compare with them, not with `bookingsOfRows` of rows that were not written, which keep what the file does not.
58
+ - **A period whose bookings were stored before 4.1.** Such bookings record no cost centres, although the Stapel sent stated them (fields 37 and 38), and `differingBookingCount` never counts them as differing on cost centres alone: a change of a cost centre only is not seen. For such a period read the file handed over back (`readExtfBuchungsstapel(bytes).rows`) and compare `bookingsOfRows` of those rows, or pass them to a correction as `handedOverRows`.
59
+ - **A correction of a period handed over.** `writeCorrectionBuchungsstapel({ handedOver, drafts, policy, header, filename })` writes only what changed since the state handed over: each booking handed over that the drafts no longer hold is written again with field 118 "Generalumkehr" set, so DATEV takes it back on its own side and day, then each row of the drafts that was not handed over; what stands in both is not written. A changed text or document link is no change; a changed cost centre is, so the booking is taken back on the cost centre DATEV received and booked on the new one. Every row keeps its Belegdatum, so it counts in the period it belongs to; a booking handed over is never replaced (§ 146 Abs. 4 AO), which also holds once DATEV has fixed the period (Festschreibung). The file names what it takes back (`reversed`), what it books (`added`) and the bookings after it (`bookingsAfter`: each booking it keeps as it was handed over, text and document link included, then the rows it books anew as the correction file states them). Both sides are compared as a file states them, so a reference the writer changes (a `"`, more than 36 characters, a character Windows-1252 cannot hold, a line break) is no change. `correctionOf(handedOver, rows)` gives `reversed`, `kept` and `added` without a file, and `rowOfBooking(booking)` the row a booking was written as.
60
+ - **The state handed over** is given once: the bookings stored of it (`handedOver`: the `bookings` of its Buchungsstapel as they were stored, by this version or by 4.1, or the last correction's `bookingsAfter`), or the rows of the Stapel as it was sent (`handedOverRows`: the transmitted file read back with `@fin.cx/skr` `readExtfBuchungsstapel(bytes).rows`, or the `rows` given to the writer). Every form compares alike. A booking stored before 4.1 has no cost-centre fields, although the Stapel sent stated them (fields 37 and 38): a correction refuses it with code `handed_over_cost_centres_unknown`, naming it, since whether it must be taken back turns on the cost centres DATEV holds and a reversal without them would not mirror it; pass `handedOverRows` for such a period. Nothing changed is refused with `nothing_to_correct`; a general reversal in the state handed over (a correction file passed as the state), or a state given twice or not at all, with `invalid_bookings`.
58
61
  - **A booking keeps its general reversal** (`IExportBooking.generalumkehr`, from field 118) and its cost centres (`kost1`, `kost2`, empty where the row states none).
59
62
 
60
63
  ```typescript
@@ -3,6 +3,6 @@
3
3
  */
4
4
  export const commitinfo = {
5
5
  name: '@fin.cx/compatibility',
6
- version: '4.1.0',
6
+ version: '5.0.0',
7
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)'
8
8
  }
package/ts/error.ts CHANGED
@@ -1,14 +1,18 @@
1
1
  /**
2
2
  * Why an exchange file could not be written:
3
- * - `invalid_bookings`: a draft the account policy refuses, the message names it; or a general reversal among the
4
- * bookings handed over to a correction Buchungsstapel (a correction file passed as the state handed over);
3
+ * - `invalid_bookings`: a draft the account policy refuses, the message names it; a general reversal among the
4
+ * bookings handed over to a correction Buchungsstapel (a correction file passed as the state handed over); or a row
5
+ * or booking a Buchungsstapel does not hold (no day, an amount that is not positive) or whose Belegdatum lies
6
+ * outside the period of the header, named;
7
+ * - `invalid_header`: a header whose period ends before it begins or does not lie within the one Wirtschaftsjahr
8
+ * beginning on its Wirtschaftsjahr-Beginn;
5
9
  * - `export_failed`: the conversion into rows failed;
6
10
  * - `invalid_documents`: a document of a document-image archive DATEV does not take (its GUID, its format), or none;
7
11
  * - `nothing_to_correct`: a correction Buchungsstapel whose current bookings are the ones handed over;
8
12
  * - `handed_over_cost_centres_unknown`: a correction of a period whose bookings handed over include one whose cost
9
13
  * centres its record does not state (stored before 4.1) and no rows sent were given; the message names it.
10
14
  */
11
- export type TCompatibilityErrorCode = 'invalid_bookings' | 'export_failed' | 'invalid_documents' | 'nothing_to_correct' | 'handed_over_cost_centres_unknown';
15
+ export type TCompatibilityErrorCode = 'invalid_bookings' | 'invalid_header' | 'export_failed' | 'invalid_documents' | 'nothing_to_correct' | 'handed_over_cost_centres_unknown';
12
16
 
13
17
  export class CompatibilityError extends Error {
14
18
  public readonly code: TCompatibilityErrorCode;
package/ts/extf/index.ts CHANGED
@@ -144,16 +144,34 @@ const pairBookings = (
144
144
  return { leftPaired, rightPaired };
145
145
  };
146
146
 
147
+ /**
148
+ * Bookings as a Buchungsstapel file states them, for comparing: each written as the row it was written as
149
+ * (`rowOfBooking`) and read back (`bookingsAsWritten`), so bookings stored of rows before writing (4.1 and before)
150
+ * and bookings read from a file compare alike. One that records no cost centres (stored before 4.1) keeps recording
151
+ * none, so it still never differs on them. A booking a Buchungsstapel cannot hold is refused (`invalid_bookings`).
152
+ */
153
+ const comparableOf = (bookingsArg: readonly IExportBooking[]): IExportBooking[] =>
154
+ bookingsAsWritten(bookingsArg.map((bookingArg) => rowOfBooking(bookingArg))).map((bookingArg, indexArg) => {
155
+ if (recordsCostCentres(bookingsArg[indexArg])) {
156
+ return bookingArg;
157
+ }
158
+ const { kost1: _kost1, kost2: _kost2, ...unrecorded } = bookingArg;
159
+ return unrecorded;
160
+ });
161
+
147
162
  /**
148
163
  * How many rows two Buchungsstapel of one period do not share, compared on
149
164
  * what a booking says (its day, amount, side, accounts, BU key, Belegfeld 1,
150
165
  * cost centres, and whether it is a general reversal) and not on its wording or its document link. The rows are
151
- * compared as a multiset: a row that stands twice in one and once in the other differs once. A booking stored before
152
- * 4.1, which does not record its cost centres, never differs on them (`pairBookings`); compare `bookingsOfRows` of
153
- * the rows sent for an answer that counts them.
166
+ * compared as a multiset: a row that stands twice in one and once in the other differs once. Both sides are compared
167
+ * as a file states them (`comparableOf`: a `"` as `'`, Belegfeld 1 cut to 36 characters, a character Windows-1252
168
+ * cannot hold as `?`), so bookings stored of rows before writing and bookings read from a file compare alike. A
169
+ * booking stored before 4.1, which does not record its cost centres, never differs on them (`pairBookings`); compare
170
+ * `bookingsOfRows` of the rows sent for an answer that counts them. A booking a Buchungsstapel cannot hold (no day,
171
+ * no positive amount) is refused (`invalid_bookings`).
154
172
  */
155
173
  export const differingBookingCount = (leftArg: readonly IExportBooking[], rightArg: readonly IExportBooking[]): number => {
156
- const { leftPaired, rightPaired } = pairBookings(leftArg, rightArg);
174
+ const { leftPaired, rightPaired } = pairBookings(comparableOf(leftArg), comparableOf(rightArg));
157
175
  return [...leftPaired, ...rightPaired].filter((pairedArg) => !pairedArg).length;
158
176
  };
159
177
 
@@ -258,7 +276,14 @@ export interface IBuchungsstapelFile {
258
276
  csv: string;
259
277
  /** the file in Windows-1252, as it is handed over */
260
278
  bytes: Uint8Array;
279
+ /** the rows as they were given to the writer; the file states them as `rowsAsWritten` does */
261
280
  rows: IDatevBuchungsstapelRow[];
281
+ /**
282
+ * The bookings the file states, read back from its bytes (`@fin.cx/skr` `readExtfBuchungsstapel`): a `"` in a
283
+ * text field as `'`, Belegfeld 1 cut to 36 characters, a character Windows-1252 cannot hold as `?`. What a file
284
+ * read back is compared with, and what a correction's `handedOver` is (4.1 and before: the rows' bookings before
285
+ * writing).
286
+ */
262
287
  bookings: IExportBooking[];
263
288
  /** the characters Windows-1252 cannot write, each written as `?`, with the row and field it stands in */
264
289
  replacedCharacters: IBuchungsstapelReplacement[];
@@ -266,6 +291,8 @@ export interface IBuchungsstapelFile {
266
291
 
267
292
  /** The file of rows: the header and the caption row, the rows, encoded in Windows-1252, with where each character stands. */
268
293
  const fileOfRows = (rows: IDatevBuchungsstapelRow[], headerArg: IDatevExtfHeaderOptions, filenameArg: string): IBuchungsstapelFile => {
294
+ refuseUnwritableRows(rows);
295
+ refuseOutsideHeader(rows, headerArg);
269
296
  const { csv } = plugins.skrCore.writeExtfBuchungsstapel(rows, headerArg);
270
297
  const { bytes, replaced } = encodeWindows1252(csv);
271
298
  // the file is the header line, the caption line and one line per row, each ending in CRLF (`writeExtfBuchungsstapel`)
@@ -291,9 +318,126 @@ const fileOfRows = (rows: IDatevBuchungsstapelRow[], headerArg: IDatevExtfHeader
291
318
  }
292
319
  return { ...replacedArg, row, field: fieldAt(fieldStartsOf(rowLines[row]), replacedArg.offset - lineStarts[row]) };
293
320
  });
294
- return { filename: filenameArg, csv, bytes, rows, bookings: bookingsOfRows(rows), replacedCharacters };
321
+ // the bookings of what was written, as the file states them
322
+ const written = plugins.skrCore.readExtfBuchungsstapel(bytes).rows;
323
+ if (written.length !== rows.length) {
324
+ throw new CompatibilityError('export_failed', `${rows.length} row(s) written, ${written.length} read back`);
325
+ }
326
+ return { filename: filenameArg, csv, bytes, rows, bookings: bookingsOfRows(written), replacedCharacters };
327
+ };
328
+
329
+ /** The Belegdatum of a row as its day, midnight UTC, in epoch milliseconds. */
330
+ const dayOfRow = (rowArg: IDatevBuchungsstapelRow): number =>
331
+ Date.UTC(rowArg.belegDatum.getUTCFullYear(), rowArg.belegDatum.getUTCMonth(), rowArg.belegDatum.getUTCDate());
332
+
333
+ /** A row as a refusal names it: its place among the rows given, its day, amount, side, accounts and Belegfeld 1. */
334
+ const rowNameOf = (rowArg: IDatevBuchungsstapelRow, indexArg: number): string =>
335
+ `row ${indexArg + 1} (${Number.isNaN(rowArg.belegDatum.getTime()) ? 'no day' : rowArg.belegDatum.toISOString().slice(0, 10)}, ${rowArg.umsatzCents} ${rowArg.sollHaben} ${rowArg.konto}/${rowArg.gegenKonto}`
336
+ + `${rowArg.belegfeld1 ? `, Belegfeld 1 ${rowArg.belegfeld1}` : ''})`;
337
+
338
+ /**
339
+ * Refuses a row a Buchungsstapel does not hold, before anything is written: a Belegdatum that is no day, and an
340
+ * amount that is not a positive whole number of cents (a Buchungsstapel states the side apart, field 2, and
341
+ * `readExtfBuchungsstapel` refuses any other). `invalid_bookings`, naming the row.
342
+ */
343
+ const refuseUnwritableRows = (rowsArg: readonly IDatevBuchungsstapelRow[]): void => {
344
+ rowsArg.forEach((rowArg, indexArg) => {
345
+ if (Number.isNaN(rowArg.belegDatum.getTime())) {
346
+ throw new CompatibilityError('invalid_bookings', `${rowNameOf(rowArg, indexArg)} has no Belegdatum`);
347
+ }
348
+ if (!Number.isSafeInteger(rowArg.umsatzCents) || rowArg.umsatzCents <= 0) {
349
+ throw new CompatibilityError('invalid_bookings', `${rowNameOf(rowArg, indexArg)}: a Buchungsstapel states a positive amount, the side apart`);
350
+ }
351
+ });
295
352
  };
296
353
 
354
+ /**
355
+ * Refuses a header whose period a Buchungsstapel cannot state (`invalid_header`): Datum von after Datum bis, or a
356
+ * period that does not lie within the one Wirtschaftsjahr beginning on the Wirtschaftsjahr-Beginn (a Belegdatum is
357
+ * written TTMM, and the reader takes its year from them); and every row whose Belegdatum lies outside the period
358
+ * (`invalid_bookings`, naming it). Checked before anything is written.
359
+ */
360
+ const refuseOutsideHeader = (rowsArg: readonly IDatevBuchungsstapelRow[], headerArg: IDatevExtfHeaderOptions): void => {
361
+ const day = (dateArg: Date): number => Date.UTC(dateArg.getUTCFullYear(), dateArg.getUTCMonth(), dateArg.getUTCDate());
362
+ const from = day(headerArg.dateFrom);
363
+ const to = day(headerArg.dateTo);
364
+ const start = day(headerArg.fiscalYearStart);
365
+ const end = Date.UTC(headerArg.fiscalYearStart.getUTCFullYear() + 1, headerArg.fiscalYearStart.getUTCMonth(), headerArg.fiscalYearStart.getUTCDate());
366
+ const iso = (timeArg: number): string => new Date(timeArg).toISOString().slice(0, 10);
367
+ if ([from, to, start].some(Number.isNaN)) {
368
+ throw new CompatibilityError('invalid_header', 'the header states no day for the Wirtschaftsjahr-Beginn, Datum von or Datum bis');
369
+ }
370
+ if (to < from) {
371
+ throw new CompatibilityError('invalid_header', `the period of the header ends (${iso(to)}) before it begins (${iso(from)})`);
372
+ }
373
+ if (from < start || to >= end) {
374
+ throw new CompatibilityError('invalid_header', `the period of the header, ${iso(from)} to ${iso(to)}, does not lie within the Wirtschaftsjahr beginning ${iso(start)}`);
375
+ }
376
+ rowsArg.forEach((rowArg, indexArg) => {
377
+ const time = dayOfRow(rowArg);
378
+ if (time < from || time > to) {
379
+ throw new CompatibilityError('invalid_bookings', `${rowNameOf(rowArg, indexArg)} lies outside the period of the header, ${iso(from)} to ${iso(to)}`);
380
+ }
381
+ });
382
+ };
383
+
384
+ /**
385
+ * Rows as a Buchungsstapel file states them: each row written by the writer (`@fin.cx/skr` `writeExtfBuchungsstapel`,
386
+ * which writes a `"` in a text field as `'` and cuts a field to its DATEV length), encoded in Windows-1252 (a
387
+ * character it cannot hold written `?`, `encodeWindows1252`), and read back (`@fin.cx/skr` `readExtfBuchungsstapel`),
388
+ * in the order given. Every rule of the writer, the encoding and the reader applies because the rows go through them,
389
+ * not through a copy of their rules. The rows of each calendar year are written as one file whose header spans their
390
+ * days; the header states nothing a row is read by beyond its days. A row the writer or the reader refuses throws as
391
+ * it does.
392
+ */
393
+ export const rowsAsWritten = (rowsArg: readonly IDatevBuchungsstapelRow[]): IDatevBuchungsstapelRow[] => {
394
+ refuseUnwritableRows(rowsArg);
395
+ const written: IDatevBuchungsstapelRow[] = new Array(rowsArg.length);
396
+ // the indexes of the rows of each calendar year, and the first and last day among them
397
+ const years = new Map<number, { indexes: number[]; first: number; last: number }>();
398
+ rowsArg.forEach((rowArg, indexArg) => {
399
+ const year = rowArg.belegDatum.getUTCFullYear();
400
+ const time = dayOfRow(rowArg);
401
+ const group = years.get(year);
402
+ if (group) {
403
+ group.indexes.push(indexArg);
404
+ group.first = Math.min(group.first, time);
405
+ group.last = Math.max(group.last, time);
406
+ } else {
407
+ years.set(year, { indexes: [indexArg], first: time, last: time });
408
+ }
409
+ });
410
+ for (const [year, group] of years) {
411
+ const { csv } = plugins.skrCore.writeExtfBuchungsstapel(group.indexes.map((indexArg) => rowsArg[indexArg]), {
412
+ createdAt: new Date(Date.UTC(year, 0, 1)),
413
+ consultantNumber: 0,
414
+ clientNumber: 0,
415
+ // a Belegdatum is written TTMM: the reader takes its year from the Wirtschaftsjahr and the period of the header
416
+ fiscalYearStart: new Date(Date.UTC(year, 0, 1)),
417
+ dateFrom: new Date(group.first),
418
+ dateTo: new Date(group.last),
419
+ label: '',
420
+ festschreibung: false,
421
+ });
422
+ const read = plugins.skrCore.readExtfBuchungsstapel(encodeWindows1252(csv).bytes).rows;
423
+ if (read.length !== group.indexes.length) {
424
+ throw new CompatibilityError('export_failed', `${group.indexes.length} row(s) written, ${read.length} read back`);
425
+ }
426
+ group.indexes.forEach((indexArg, positionArg) => {
427
+ written[indexArg] = read[positionArg];
428
+ });
429
+ }
430
+ return written;
431
+ };
432
+
433
+ /**
434
+ * The bookings of rows as a Buchungsstapel file states them (`rowsAsWritten`): what a file handed over, read back
435
+ * with `readExtfBuchungsstapel`, is compared with. `bookingsOfRows` of the rows before writing keeps what the file
436
+ * does not (a `"` in Belegfeld 1, a Belegfeld 1 longer than its 36 characters, a character Windows-1252 cannot
437
+ * hold), and Belegfeld 1 is compared, so such a booking would differ from the file forever.
438
+ */
439
+ export const bookingsAsWritten = (rowsArg: readonly IDatevBuchungsstapelRow[]): IExportBooking[] => bookingsOfRows(rowsAsWritten(rowsArg));
440
+
297
441
  /** Writes a Buchungsstapel: the rows of the drafts, the header and the caption row, encoded in Windows-1252. */
298
442
  export const writeBuchungsstapel = (optionsArg: IBuchungsstapelOptions): IBuchungsstapelFile =>
299
443
  fileOfRows(datevRowsOf(optionsArg.drafts, optionsArg.policy), optionsArg.header, optionsArg.filename);
@@ -345,15 +489,18 @@ const refuseCostCentresUnknown = (handedOverArg: readonly IExportBooking[]): voi
345
489
  * handed over that the current ones no longer hold (`reversed`, each once for each time it is missing), the ones they
346
490
  * still hold (`kept`, as they were handed over) and the current rows the bookings handed over do not hold (`added`),
347
491
  * each in its order. A booking that stands in both is kept: a changed text or document link is no changed booking,
348
- * a changed cost centre is. A booking handed over whose cost centres its record does not state (stored before 4.1)
349
- * is refused (`handed_over_cost_centres_unknown`): pass `bookingsOfRows` of the rows sent instead.
492
+ * a changed cost centre is. The current rows are compared as a file states them (`bookingsAsWritten`), as the
493
+ * bookings handed over are; `added` are the rows themselves, which the writer writes. A booking handed over whose
494
+ * cost centres its record does not state (stored before 4.1) is refused (`handed_over_cost_centres_unknown`): pass
495
+ * `bookingsOfRows` of the rows sent instead.
350
496
  */
351
497
  export const correctionOf = (
352
498
  handedOverArg: readonly IExportBooking[],
353
499
  currentArg: readonly IDatevBuchungsstapelRow[],
354
500
  ): { reversed: IExportBooking[]; kept: IExportBooking[]; added: IDatevBuchungsstapelRow[] } => {
355
501
  refuseCostCentresUnknown(handedOverArg);
356
- const { leftPaired, rightPaired } = pairBookings(handedOverArg, bookingsOfRows(currentArg));
502
+ // the current rows as a file states them, as the state handed over was: a reference the writer changes is the same
503
+ const { leftPaired, rightPaired } = pairBookings(comparableOf(handedOverArg), bookingsAsWritten(currentArg));
357
504
  return {
358
505
  reversed: handedOverArg.filter((_bookingArg, indexArg) => !leftPaired[indexArg]),
359
506
  kept: handedOverArg.filter((_bookingArg, indexArg) => leftPaired[indexArg]),
@@ -371,14 +518,16 @@ export interface ICorrectionBuchungsstapelOptions {
371
518
  * The bookings of the period as they were handed over, as a whole: the bookings of its Buchungsstapel as stored
372
519
  * (`IBuchungsstapelFile.bookings`), or after a correction the period's bookings as that correction left them
373
520
  * (`bookingsAfter`). Each must state its cost centres: one stored before 4.1 does not, and is refused
374
- * (`handed_over_cost_centres_unknown`); pass the rows sent for it.
521
+ * (`handed_over_cost_centres_unknown`); pass the rows sent for it. Bookings stored by any version, before or after
522
+ * writing, are compared as a file states them (`comparableOf`), so a reference the writer changed is no change.
375
523
  */
376
524
  handedOver?: readonly IExportBooking[];
377
525
  /**
378
526
  * The rows of the Buchungsstapel as it was sent: the transmitted file read back (`@fin.cx/skr`
379
- * `readExtfBuchungsstapel(bytes).rows`, skr 6.1.0 and later) or the rows written (`IBuchungsstapelFile.rows`). What
380
- * DATEV received, cost centres (fields 37 and 38) included, so a reversal mirrors it exactly. For a Stapel whose
381
- * bookings were stored before 4.1.
527
+ * `readExtfBuchungsstapel(bytes).rows`, skr 7.0.1 and later) or the rows given to the writer
528
+ * (`IBuchungsstapelFile.rows`), taken as the file states them (`bookingsAsWritten`). What DATEV received, cost
529
+ * centres (fields 37 and 38) included, so a reversal mirrors it exactly. For a Stapel whose bookings were stored
530
+ * before 4.1, which record no cost centres.
382
531
  */
383
532
  handedOverRows?: readonly IDatevBuchungsstapelRow[];
384
533
  /** the period's drafts as they stand now */
@@ -413,7 +562,8 @@ export interface ICorrectionBuchungsstapelFile extends IBuchungsstapelFile {
413
562
  * twice or not at all; `handed_over_cost_centres_unknown` for a booking whose cost centres are not known.
414
563
  */
415
564
  export const writeCorrectionBuchungsstapel = (optionsArg: ICorrectionBuchungsstapelOptions): ICorrectionBuchungsstapelFile => {
416
- const handedOver = optionsArg.handedOverRows !== undefined ? bookingsOfRows(optionsArg.handedOverRows) : optionsArg.handedOver;
565
+ // rows read back from the file sent are as written already; rows given to the writer become what it wrote
566
+ const handedOver = optionsArg.handedOverRows !== undefined ? bookingsAsWritten(optionsArg.handedOverRows) : optionsArg.handedOver;
417
567
  if (handedOver === undefined || (optionsArg.handedOver !== undefined && optionsArg.handedOverRows !== undefined)) {
418
568
  throw new CompatibilityError('invalid_bookings', 'pass the state handed over once: the bookings stored (handedOver) or the rows sent (handedOverRows)');
419
569
  }
@@ -427,5 +577,7 @@ export const writeCorrectionBuchungsstapel = (optionsArg: ICorrectionBuchungssta
427
577
  throw new CompatibilityError('nothing_to_correct', 'the bookings of the period are the ones handed over; there is nothing to correct');
428
578
  }
429
579
  const rows = [...reversed.map((bookingArg) => ({ ...rowOfBooking(bookingArg), generalumkehr: true })), ...added];
430
- return { ...fileOfRows(rows, optionsArg.header, optionsArg.filename), reversed, added, bookingsAfter: [...kept, ...bookingsOfRows(added)] };
580
+ const file = fileOfRows(rows, optionsArg.header, optionsArg.filename);
581
+ // the rows booked anew as the correction file states them, after the reversals
582
+ return { ...file, reversed, added, bookingsAfter: [...kept, ...file.bookings.slice(reversed.length)] };
431
583
  };