@fin.cx/compatibility 3.0.0 → 4.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.
- package/dist_ts/00_commitinfo_data.js +1 -1
- package/dist_ts/error.d.ts +7 -3
- package/dist_ts/error.js +1 -1
- package/dist_ts/extf/index.d.ts +86 -3
- package/dist_ts/extf/index.js +168 -28
- package/package.json +6 -3
- package/readme.md +7 -2
- package/ts/00_commitinfo_data.ts +1 -1
- package/ts/error.ts +7 -3
- package/ts/extf/index.ts +244 -27
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
*/
|
|
4
4
|
export const commitinfo = {
|
|
5
5
|
name: '@fin.cx/compatibility',
|
|
6
|
-
version: '
|
|
6
|
+
version: '4.1.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=
|
package/dist_ts/error.d.ts
CHANGED
|
@@ -1,10 +1,14 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Why an exchange file could not be written:
|
|
3
|
-
* - `invalid_bookings`: a draft the account policy refuses
|
|
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);
|
|
4
5
|
* - `export_failed`: the conversion into rows failed;
|
|
5
|
-
* - `invalid_documents`: a document of a document-image archive DATEV does not take (its GUID, its format), or none
|
|
6
|
+
* - `invalid_documents`: a document of a document-image archive DATEV does not take (its GUID, its format), or none;
|
|
7
|
+
* - `nothing_to_correct`: a correction Buchungsstapel whose current bookings are the ones handed over;
|
|
8
|
+
* - `handed_over_cost_centres_unknown`: a correction of a period whose bookings handed over include one whose cost
|
|
9
|
+
* centres its record does not state (stored before 4.1) and no rows sent were given; the message names it.
|
|
6
10
|
*/
|
|
7
|
-
export type TCompatibilityErrorCode = 'invalid_bookings' | 'export_failed' | 'invalid_documents';
|
|
11
|
+
export type TCompatibilityErrorCode = 'invalid_bookings' | 'export_failed' | 'invalid_documents' | 'nothing_to_correct' | 'handed_over_cost_centres_unknown';
|
|
8
12
|
export declare class CompatibilityError extends Error {
|
|
9
13
|
readonly code: TCompatibilityErrorCode;
|
|
10
14
|
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,
|
|
8
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZXJyb3IuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi90cy9lcnJvci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFZQSxNQUFNLE9BQU8sa0JBQW1CLFNBQVEsS0FBSztJQUczQyxZQUFZLE9BQWdDLEVBQUUsVUFBa0I7UUFDOUQsS0FBSyxDQUFDLFVBQVUsQ0FBQyxDQUFDO1FBQ2xCLElBQUksQ0FBQyxJQUFJLEdBQUcsb0JBQW9CLENBQUM7UUFDakMsSUFBSSxDQUFDLElBQUksR0FBRyxPQUFPLENBQUM7SUFDdEIsQ0FBQztDQUNGIn0=
|
package/dist_ts/extf/index.d.ts
CHANGED
|
@@ -21,14 +21,29 @@ export interface IExportBooking {
|
|
|
21
21
|
text: string;
|
|
22
22
|
/** the document GUID the row links to (field 20, `BEDI "GUID"`) */
|
|
23
23
|
documentGuid?: string;
|
|
24
|
+
/**
|
|
25
|
+
* The cost centres of the row (fields 37 and 38, KOST1 and KOST2), empty where it states none. `bookingsOfRows`
|
|
26
|
+
* records both on every booking; a booking stored before 4.1 has neither, although the row sent stated them: its
|
|
27
|
+
* cost centres are not known. `differingBookingCount` compares it without them; a correction refuses it
|
|
28
|
+
* (`handed_over_cost_centres_unknown`) unless it is given the rows sent (`handedOverRows`).
|
|
29
|
+
*/
|
|
30
|
+
kost1?: string;
|
|
31
|
+
kost2?: string;
|
|
32
|
+
/**
|
|
33
|
+
* The row is a general reversal (field 118 "Generalumkehr", written "1"): it takes back the booking of the same
|
|
34
|
+
* fields on DATEV's side. Absent on an ordinary row.
|
|
35
|
+
*/
|
|
36
|
+
generalumkehr?: true;
|
|
24
37
|
}
|
|
25
38
|
/** The bookings of rows, in their order. */
|
|
26
39
|
export declare const bookingsOfRows: (rowsArg: readonly IDatevBuchungsstapelRow[]) => IExportBooking[];
|
|
27
40
|
/**
|
|
28
41
|
* How many rows two Buchungsstapel of one period do not share, compared on
|
|
29
|
-
* what a booking says (its day, amount, side, accounts, BU key
|
|
30
|
-
*
|
|
31
|
-
* multiset: a row that stands twice in one and once in the other differs once.
|
|
42
|
+
* what a booking says (its day, amount, side, accounts, BU key, Belegfeld 1,
|
|
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.
|
|
32
47
|
*/
|
|
33
48
|
export declare const differingBookingCount: (leftArg: readonly IExportBooking[], rightArg: readonly IExportBooking[]) => number;
|
|
34
49
|
/**
|
|
@@ -88,3 +103,71 @@ export interface IBuchungsstapelFile {
|
|
|
88
103
|
}
|
|
89
104
|
/** Writes a Buchungsstapel: the rows of the drafts, the header and the caption row, encoded in Windows-1252. */
|
|
90
105
|
export declare const writeBuchungsstapel: (optionsArg: IBuchungsstapelOptions) => IBuchungsstapelFile;
|
|
106
|
+
/**
|
|
107
|
+
* The row a booking handed over was written as, for a general reversal of it: every field the booking keeps
|
|
108
|
+
* (`IExportBooking`) in its place, the Belegdatum at midnight UTC as the writer reads it.
|
|
109
|
+
*/
|
|
110
|
+
export declare const rowOfBooking: (bookingArg: IExportBooking) => IDatevBuchungsstapelRow;
|
|
111
|
+
/**
|
|
112
|
+
* What a correction of a period handed over changes, compared as `differingBookingCount` compares: the bookings
|
|
113
|
+
* handed over that the current ones no longer hold (`reversed`, each once for each time it is missing), the ones they
|
|
114
|
+
* still hold (`kept`, as they were handed over) and the current rows the bookings handed over do not hold (`added`),
|
|
115
|
+
* 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.
|
|
118
|
+
*/
|
|
119
|
+
export declare const correctionOf: (handedOverArg: readonly IExportBooking[], currentArg: readonly IDatevBuchungsstapelRow[]) => {
|
|
120
|
+
reversed: IExportBooking[];
|
|
121
|
+
kept: IExportBooking[];
|
|
122
|
+
added: IDatevBuchungsstapelRow[];
|
|
123
|
+
};
|
|
124
|
+
/**
|
|
125
|
+
* The state of a period handed over, given once: the bookings stored of it (`handedOver`) or the rows of the Stapel
|
|
126
|
+
* sent (`handedOverRows`). A general reversal in it is refused: the state handed over is compared, not a correction
|
|
127
|
+
* file.
|
|
128
|
+
*/
|
|
129
|
+
export interface ICorrectionBuchungsstapelOptions {
|
|
130
|
+
/**
|
|
131
|
+
* The bookings of the period as they were handed over, as a whole: the bookings of its Buchungsstapel as stored
|
|
132
|
+
* (`IBuchungsstapelFile.bookings`), or after a correction the period's bookings as that correction left them
|
|
133
|
+
* (`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.
|
|
135
|
+
*/
|
|
136
|
+
handedOver?: readonly IExportBooking[];
|
|
137
|
+
/**
|
|
138
|
+
* 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.
|
|
142
|
+
*/
|
|
143
|
+
handedOverRows?: readonly IDatevBuchungsstapelRow[];
|
|
144
|
+
/** the period's drafts as they stand now */
|
|
145
|
+
drafts: readonly plugins.skrCore.IJournalDraft[];
|
|
146
|
+
/** the policy the drafts are checked against */
|
|
147
|
+
policy: plugins.skrCore.IAccountPolicy;
|
|
148
|
+
/** the header of the file: the same period (`dateFrom`, `dateTo`) as the Stapel handed over, a label of its own */
|
|
149
|
+
header: IDatevExtfHeaderOptions;
|
|
150
|
+
filename: string;
|
|
151
|
+
}
|
|
152
|
+
export interface ICorrectionBuchungsstapelFile extends IBuchungsstapelFile {
|
|
153
|
+
/** the bookings handed over it takes back, each written as a general reversal */
|
|
154
|
+
reversed: IExportBooking[];
|
|
155
|
+
/** the rows it books anew */
|
|
156
|
+
added: IDatevBuchungsstapelRow[];
|
|
157
|
+
/**
|
|
158
|
+
* The period's bookings as DATEV holds them after this correction: each booking handed over that it keeps, as it
|
|
159
|
+
* was handed over (its text and document link too), then the rows it books anew. What the next correction is
|
|
160
|
+
* compared against.
|
|
161
|
+
*/
|
|
162
|
+
bookingsAfter: IExportBooking[];
|
|
163
|
+
}
|
|
164
|
+
/**
|
|
165
|
+
* Writes the correction Buchungsstapel of a period handed over whose bookings changed since: only what changed. Each
|
|
166
|
+
* booking handed over that the drafts no longer hold is written again with field 118 "Generalumkehr" set, so DATEV
|
|
167
|
+
* takes it back on its side and day, and each row the drafts hold that was not handed over is written as it is; rows
|
|
168
|
+
* in both are not written. Every row keeps its Belegdatum, so it counts in the period it belongs to. A booking handed
|
|
169
|
+
* over is never changed or replaced (§ 146 Abs. 4 AO): it is taken back and booked anew. Throws `nothing_to_correct`
|
|
170
|
+
* when nothing changed; `invalid_bookings` for a general reversal in the state handed over, or for a state given
|
|
171
|
+
* twice or not at all; `handed_over_cost_centres_unknown` for a booking whose cost centres are not known.
|
|
172
|
+
*/
|
|
173
|
+
export declare const writeCorrectionBuchungsstapel: (optionsArg: ICorrectionBuchungsstapelOptions) => ICorrectionBuchungsstapelFile;
|
package/dist_ts/extf/index.js
CHANGED
|
@@ -20,33 +20,94 @@ export const bookingsOfRows = (rowsArg) => rowsArg.map((rowArg) => ({
|
|
|
20
20
|
...(rowArg.belegfeld2 ? { belegfeld2: rowArg.belegfeld2 } : {}),
|
|
21
21
|
text: rowArg.buchungstext,
|
|
22
22
|
...(rowArg.belegLink ? { documentGuid: guidOfLink(rowArg.belegLink) } : {}),
|
|
23
|
+
// recorded on every booking, empty where the row states none: a booking without them was stored before 4.1
|
|
24
|
+
kost1: rowArg.kost1 ?? '',
|
|
25
|
+
kost2: rowArg.kost2 ?? '',
|
|
26
|
+
...(rowArg.generalumkehr === true ? { generalumkehr: true } : {}),
|
|
23
27
|
}));
|
|
24
28
|
/**
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
* multiset: a row that stands twice in one and once in the other differs once.
|
|
29
|
+
* What a booking says, as two Stapel of one period are compared, apart from its cost centres: its day, amount, side,
|
|
30
|
+
* accounts, BU key, Belegfeld 1 and whether it is a general reversal, not its wording or document link. A reversal
|
|
31
|
+
* never matches an ordinary row.
|
|
29
32
|
*/
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
33
|
+
const baseKeyOf = (bookingArg) => JSON.stringify([
|
|
34
|
+
bookingArg.date,
|
|
35
|
+
bookingArg.umsatzCents,
|
|
36
|
+
bookingArg.sollHaben,
|
|
37
|
+
bookingArg.konto,
|
|
38
|
+
bookingArg.gegenkonto,
|
|
39
|
+
bookingArg.buKey,
|
|
40
|
+
bookingArg.belegfeld1 ?? '',
|
|
41
|
+
bookingArg.generalumkehr ? 'GU' : '',
|
|
42
|
+
]);
|
|
43
|
+
/** Whether a booking records its cost centres: every booking read from rows since 4.1 does, one stored before does not. */
|
|
44
|
+
const recordsCostCentres = (bookingArg) => bookingArg.kost1 !== undefined || bookingArg.kost2 !== undefined;
|
|
45
|
+
/** What a booking that records its cost centres says, the cost centres included. */
|
|
46
|
+
const fullKeyOf = (bookingArg) => JSON.stringify([baseKeyOf(bookingArg), bookingArg.kost1 ?? '', bookingArg.kost2 ?? '']);
|
|
47
|
+
/**
|
|
48
|
+
* Pairs the bookings of two Stapel of one period that say the same, as a multiset: two bookings that record their
|
|
49
|
+
* cost centres pair on every key field, the cost centres included, so a changed cost centre is a changed booking. A
|
|
50
|
+
* booking that does not record them (stored before 4.1, although the row sent stated them) pairs with any booking of
|
|
51
|
+
* the same other key fields: its record says nothing of them, so they never make it differ. Unpaired recorded bookings take the
|
|
52
|
+
* unrecorded ones of the other side first, which pair with anything, so as many pairs as possible are made.
|
|
53
|
+
*/
|
|
54
|
+
const pairBookings = (leftArg, rightArg) => {
|
|
55
|
+
const leftPaired = leftArg.map(() => false);
|
|
56
|
+
const rightPaired = rightArg.map(() => false);
|
|
57
|
+
const take = (queuesArg, keyArg) => queuesArg.get(keyArg)?.shift();
|
|
58
|
+
const queue = (queuesArg, keyArg, indexArg) => {
|
|
59
|
+
queuesArg.set(keyArg, [...(queuesArg.get(keyArg) ?? []), indexArg]);
|
|
60
|
+
};
|
|
61
|
+
// recorded with recorded, on every key field
|
|
62
|
+
const recordedRight = new Map();
|
|
63
|
+
rightArg.forEach((bookingArg, indexArg) => {
|
|
64
|
+
if (recordsCostCentres(bookingArg)) {
|
|
65
|
+
queue(recordedRight, fullKeyOf(bookingArg), indexArg);
|
|
41
66
|
}
|
|
42
|
-
|
|
43
|
-
|
|
67
|
+
});
|
|
68
|
+
leftArg.forEach((bookingArg, indexArg) => {
|
|
69
|
+
const paired = recordsCostCentres(bookingArg) ? take(recordedRight, fullKeyOf(bookingArg)) : undefined;
|
|
70
|
+
if (paired !== undefined) {
|
|
71
|
+
leftPaired[indexArg] = true;
|
|
72
|
+
rightPaired[paired] = true;
|
|
44
73
|
}
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
74
|
+
});
|
|
75
|
+
// what is left, on the key fields without the cost centres, where one of the two does not record them
|
|
76
|
+
const unrecordedRight = new Map();
|
|
77
|
+
const openRecordedRight = new Map();
|
|
78
|
+
rightArg.forEach((bookingArg, indexArg) => {
|
|
79
|
+
if (!rightPaired[indexArg]) {
|
|
80
|
+
queue(recordsCostCentres(bookingArg) ? openRecordedRight : unrecordedRight, baseKeyOf(bookingArg), indexArg);
|
|
81
|
+
}
|
|
82
|
+
});
|
|
83
|
+
const pairLeft = (recordedArg) => {
|
|
84
|
+
leftArg.forEach((bookingArg, indexArg) => {
|
|
85
|
+
if (leftPaired[indexArg] || recordsCostCentres(bookingArg) !== recordedArg) {
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
const key = baseKeyOf(bookingArg);
|
|
89
|
+
const paired = recordedArg ? take(unrecordedRight, key) : take(openRecordedRight, key) ?? take(unrecordedRight, key);
|
|
90
|
+
if (paired !== undefined) {
|
|
91
|
+
leftPaired[indexArg] = true;
|
|
92
|
+
rightPaired[paired] = true;
|
|
93
|
+
}
|
|
94
|
+
});
|
|
95
|
+
};
|
|
96
|
+
pairLeft(true);
|
|
97
|
+
pairLeft(false);
|
|
98
|
+
return { leftPaired, rightPaired };
|
|
99
|
+
};
|
|
100
|
+
/**
|
|
101
|
+
* How many rows two Buchungsstapel of one period do not share, compared on
|
|
102
|
+
* what a booking says (its day, amount, side, accounts, BU key, Belegfeld 1,
|
|
103
|
+
* 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.
|
|
107
|
+
*/
|
|
108
|
+
export const differingBookingCount = (leftArg, rightArg) => {
|
|
109
|
+
const { leftPaired, rightPaired } = pairBookings(leftArg, rightArg);
|
|
110
|
+
return [...leftPaired, ...rightPaired].filter((pairedArg) => !pairedArg).length;
|
|
50
111
|
};
|
|
51
112
|
/**
|
|
52
113
|
* Checks every draft against the account policy and turns the drafts into
|
|
@@ -109,10 +170,9 @@ export const replacedCharactersOfRows = (rowsArg) => {
|
|
|
109
170
|
});
|
|
110
171
|
return replacements;
|
|
111
172
|
};
|
|
112
|
-
/**
|
|
113
|
-
|
|
114
|
-
const
|
|
115
|
-
const { csv } = plugins.skrCore.writeExtfBuchungsstapel(rows, optionsArg.header);
|
|
173
|
+
/** The file of rows: the header and the caption row, the rows, encoded in Windows-1252, with where each character stands. */
|
|
174
|
+
const fileOfRows = (rows, headerArg, filenameArg) => {
|
|
175
|
+
const { csv } = plugins.skrCore.writeExtfBuchungsstapel(rows, headerArg);
|
|
116
176
|
const { bytes, replaced } = encodeWindows1252(csv);
|
|
117
177
|
// the file is the header line, the caption line and one line per row, each ending in CRLF (`writeExtfBuchungsstapel`)
|
|
118
178
|
const rowLines = rows.map((rowArg) => plugins.skrCore.datevRowFields(rowArg));
|
|
@@ -137,6 +197,86 @@ export const writeBuchungsstapel = (optionsArg) => {
|
|
|
137
197
|
}
|
|
138
198
|
return { ...replacedArg, row, field: fieldAt(fieldStartsOf(rowLines[row]), replacedArg.offset - lineStarts[row]) };
|
|
139
199
|
});
|
|
140
|
-
return { filename:
|
|
200
|
+
return { filename: filenameArg, csv, bytes, rows, bookings: bookingsOfRows(rows), replacedCharacters };
|
|
201
|
+
};
|
|
202
|
+
/** Writes a Buchungsstapel: the rows of the drafts, the header and the caption row, encoded in Windows-1252. */
|
|
203
|
+
export const writeBuchungsstapel = (optionsArg) => fileOfRows(datevRowsOf(optionsArg.drafts, optionsArg.policy), optionsArg.header, optionsArg.filename);
|
|
204
|
+
/**
|
|
205
|
+
* The row a booking handed over was written as, for a general reversal of it: every field the booking keeps
|
|
206
|
+
* (`IExportBooking`) in its place, the Belegdatum at midnight UTC as the writer reads it.
|
|
207
|
+
*/
|
|
208
|
+
export const rowOfBooking = (bookingArg) => ({
|
|
209
|
+
umsatzCents: bookingArg.umsatzCents,
|
|
210
|
+
sollHaben: bookingArg.sollHaben,
|
|
211
|
+
konto: bookingArg.konto,
|
|
212
|
+
gegenKonto: bookingArg.gegenkonto,
|
|
213
|
+
buSchluessel: bookingArg.buKey,
|
|
214
|
+
belegDatum: new Date(`${bookingArg.date}T00:00:00.000Z`),
|
|
215
|
+
...(bookingArg.belegfeld1 ? { belegfeld1: bookingArg.belegfeld1 } : {}),
|
|
216
|
+
...(bookingArg.belegfeld2 ? { belegfeld2: bookingArg.belegfeld2 } : {}),
|
|
217
|
+
buchungstext: bookingArg.text,
|
|
218
|
+
...(bookingArg.documentGuid ? { belegLink: bookingArg.documentGuid } : {}),
|
|
219
|
+
...(bookingArg.kost1 ? { kost1: bookingArg.kost1 } : {}),
|
|
220
|
+
...(bookingArg.kost2 ? { kost2: bookingArg.kost2 } : {}),
|
|
221
|
+
festschreibung: false,
|
|
222
|
+
...(bookingArg.generalumkehr ? { generalumkehr: true } : {}),
|
|
223
|
+
});
|
|
224
|
+
/** A booking as a refusal names it: its place among the bookings handed over, day, amount, side, accounts and Belegfeld 1. */
|
|
225
|
+
const bookingNameOf = (bookingArg, indexArg) => `booking ${indexArg + 1} (${bookingArg.date}, ${bookingArg.umsatzCents} ${bookingArg.sollHaben} ${bookingArg.konto}/${bookingArg.gegenkonto}`
|
|
226
|
+
+ `${bookingArg.belegfeld1 ? `, Belegfeld 1 ${bookingArg.belegfeld1}` : ''})`;
|
|
227
|
+
/**
|
|
228
|
+
* Refuses a state handed over that holds a booking whose cost centres its record does not state (stored before 4.1).
|
|
229
|
+
* The Stapel sent stated them (fields 37 and 38), so DATEV holds them: whether the booking must be taken back turns on
|
|
230
|
+
* them, and a reversal that does not state them would leave them standing in DATEV's cost accounting. The rows sent
|
|
231
|
+
* tell them (`handedOverRows`).
|
|
232
|
+
*/
|
|
233
|
+
const refuseCostCentresUnknown = (handedOverArg) => {
|
|
234
|
+
const unknown = handedOverArg.findIndex((bookingArg) => !recordsCostCentres(bookingArg));
|
|
235
|
+
if (unknown >= 0) {
|
|
236
|
+
throw new CompatibilityError('handed_over_cost_centres_unknown', `${bookingNameOf(handedOverArg[unknown], unknown)} was stored without the cost centres it was sent with; pass the rows of the Stapel sent (handedOverRows)`);
|
|
237
|
+
}
|
|
238
|
+
};
|
|
239
|
+
/**
|
|
240
|
+
* What a correction of a period handed over changes, compared as `differingBookingCount` compares: the bookings
|
|
241
|
+
* handed over that the current ones no longer hold (`reversed`, each once for each time it is missing), the ones they
|
|
242
|
+
* still hold (`kept`, as they were handed over) and the current rows the bookings handed over do not hold (`added`),
|
|
243
|
+
* 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.
|
|
246
|
+
*/
|
|
247
|
+
export const correctionOf = (handedOverArg, currentArg) => {
|
|
248
|
+
refuseCostCentresUnknown(handedOverArg);
|
|
249
|
+
const { leftPaired, rightPaired } = pairBookings(handedOverArg, bookingsOfRows(currentArg));
|
|
250
|
+
return {
|
|
251
|
+
reversed: handedOverArg.filter((_bookingArg, indexArg) => !leftPaired[indexArg]),
|
|
252
|
+
kept: handedOverArg.filter((_bookingArg, indexArg) => leftPaired[indexArg]),
|
|
253
|
+
added: currentArg.filter((_rowArg, indexArg) => !rightPaired[indexArg]),
|
|
254
|
+
};
|
|
255
|
+
};
|
|
256
|
+
/**
|
|
257
|
+
* Writes the correction Buchungsstapel of a period handed over whose bookings changed since: only what changed. Each
|
|
258
|
+
* booking handed over that the drafts no longer hold is written again with field 118 "Generalumkehr" set, so DATEV
|
|
259
|
+
* takes it back on its side and day, and each row the drafts hold that was not handed over is written as it is; rows
|
|
260
|
+
* in both are not written. Every row keeps its Belegdatum, so it counts in the period it belongs to. A booking handed
|
|
261
|
+
* over is never changed or replaced (§ 146 Abs. 4 AO): it is taken back and booked anew. Throws `nothing_to_correct`
|
|
262
|
+
* when nothing changed; `invalid_bookings` for a general reversal in the state handed over, or for a state given
|
|
263
|
+
* twice or not at all; `handed_over_cost_centres_unknown` for a booking whose cost centres are not known.
|
|
264
|
+
*/
|
|
265
|
+
export const writeCorrectionBuchungsstapel = (optionsArg) => {
|
|
266
|
+
const handedOver = optionsArg.handedOverRows !== undefined ? bookingsOfRows(optionsArg.handedOverRows) : optionsArg.handedOver;
|
|
267
|
+
if (handedOver === undefined || (optionsArg.handedOver !== undefined && optionsArg.handedOverRows !== undefined)) {
|
|
268
|
+
throw new CompatibilityError('invalid_bookings', 'pass the state handed over once: the bookings stored (handedOver) or the rows sent (handedOverRows)');
|
|
269
|
+
}
|
|
270
|
+
const reversal = handedOver.findIndex((bookingArg) => bookingArg.generalumkehr === true);
|
|
271
|
+
if (reversal >= 0) {
|
|
272
|
+
throw new CompatibilityError('invalid_bookings', `the state handed over holds a general reversal (booking ${reversal + 1}); pass the period's bookings as they stood, not a correction file`);
|
|
273
|
+
}
|
|
274
|
+
const current = datevRowsOf(optionsArg.drafts, optionsArg.policy);
|
|
275
|
+
const { reversed, kept, added } = correctionOf(handedOver, current);
|
|
276
|
+
if (reversed.length === 0 && added.length === 0) {
|
|
277
|
+
throw new CompatibilityError('nothing_to_correct', 'the bookings of the period are the ones handed over; there is nothing to correct');
|
|
278
|
+
}
|
|
279
|
+
const rows = [...reversed.map((bookingArg) => ({ ...rowOfBooking(bookingArg), generalumkehr: true })), ...added];
|
|
280
|
+
return { ...fileOfRows(rows, optionsArg.header, optionsArg.filename), reversed, added, bookingsAfter: [...kept, ...bookingsOfRows(added)] };
|
|
141
281
|
};
|
|
142
|
-
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi90cy9leHRmL2luZGV4LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sS0FBSyxPQUFPLE1BQU0sY0FBYyxDQUFDO0FBQ3hDLE9BQU8sRUFBRSxrQkFBa0IsRUFBRSxNQUFNLGFBQWEsQ0FBQztBQUNqRCxPQUFPLEVBQUUsaUJBQWlCLEVBQTJCLE1BQU0sc0JBQXNCLENBQUM7QUFFbEYsT0FBTyxFQUFFLGtCQUFrQixFQUFnQyxNQUFNLGFBQWEsQ0FBQztBQUsvRSxzRkFBc0Y7QUFDdEYsTUFBTSxDQUFDLE1BQU0saUJBQWlCLEdBQUcsZ0NBQWdDLENBQUM7QUFFbEUsd0ZBQXdGO0FBQ3hGLE1BQU0sQ0FBQyxNQUFNLFlBQVksR0FBRyxDQUFDLFFBQWdCLEVBQVUsRUFBRSxDQUFDLHVCQUF1QixRQUFRLE1BQU0sQ0FBQztBQWtCaEcsMEVBQTBFO0FBQzFFLE1BQU0sVUFBVSxHQUFHLENBQUMsT0FBZSxFQUFVLEVBQUUsQ0FBQyxPQUFPLENBQUMsT0FBTyxDQUFDLFlBQVksRUFBRSxFQUFFLENBQUMsQ0FBQyxPQUFPLENBQUMsV0FBVyxFQUFFLEVBQUUsQ0FBQyxDQUFDLElBQUksRUFBRSxDQUFDO0FBRWxILDRDQUE0QztBQUM1QyxNQUFNLENBQUMsTUFBTSxjQUFjLEdBQUcsQ0FBQyxPQUEyQyxFQUFvQixFQUFFLENBQzlGLE9BQU8sQ0FBQyxHQUFHLENBQUMsQ0FBQyxNQUFNLEVBQUUsRUFBRSxDQUFDLENBQUM7SUFDdkIsV0FBVyxFQUFFLE1BQU0sQ0FBQyxXQUFXO0lBQy9CLFNBQVMsRUFBRSxNQUFNLENBQUMsU0FBUztJQUMzQixLQUFLLEVBQUUsTUFBTSxDQUFDLEtBQUs7SUFDbkIsVUFBVSxFQUFFLE1BQU0sQ0FBQyxVQUFVO0lBQzdCLEtBQUssRUFBRSxNQUFNLENBQUMsWUFBWTtJQUMxQixJQUFJLEVBQUUsTUFBTSxDQUFDLFVBQVUsQ0FBQyxXQUFXLEVB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
|
|
282
|
+
//# 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": "
|
|
3
|
+
"version": "4.1.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",
|
|
@@ -42,12 +42,12 @@
|
|
|
42
42
|
},
|
|
43
43
|
"homepage": "https://code.foss.global/fin.cx/compatibility#readme",
|
|
44
44
|
"dependencies": {
|
|
45
|
-
"@fin.cx/skr": "^5.2.0",
|
|
46
45
|
"@push.rocks/smartarchive": "^5.4.1"
|
|
47
46
|
},
|
|
48
47
|
"devDependencies": {
|
|
48
|
+
"@fin.cx/skr": "^6.0.0",
|
|
49
49
|
"@git.zone/tsbuild": "^5.0.0",
|
|
50
|
-
"@git.zone/tsrun": "^3.0.
|
|
50
|
+
"@git.zone/tsrun": "^3.0.2",
|
|
51
51
|
"@git.zone/tstest": "^6.3.2",
|
|
52
52
|
"@types/node": "^26.6.2"
|
|
53
53
|
},
|
|
@@ -57,6 +57,9 @@
|
|
|
57
57
|
"readme.md",
|
|
58
58
|
"license.md"
|
|
59
59
|
],
|
|
60
|
+
"peerDependencies": {
|
|
61
|
+
"@fin.cx/skr": "^6.0.0"
|
|
62
|
+
},
|
|
60
63
|
"scripts": {
|
|
61
64
|
"test": "(tstest test/ --verbose)",
|
|
62
65
|
"build": "(tsbuild)",
|
package/readme.md
CHANGED
|
@@ -14,9 +14,11 @@ For reporting bugs, issues, or security vulnerabilities, please visit [community
|
|
|
14
14
|
## Install
|
|
15
15
|
|
|
16
16
|
```bash
|
|
17
|
-
pnpm install @fin.cx/compatibility
|
|
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.
|
|
21
|
+
|
|
20
22
|
## Usage
|
|
21
23
|
|
|
22
24
|
```typescript
|
|
@@ -50,7 +52,10 @@ file.replacedCharacters; // [{ offset, character: 'ő', row: 1, field: 14 }, …
|
|
|
50
52
|
- **A draft the account policy refuses** throws `CompatibilityError` with code `invalid_bookings` and a message naming the draft.
|
|
51
53
|
- **A failed conversion** throws code `export_failed`.
|
|
52
54
|
- **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`.
|
|
53
|
-
- **`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
|
|
55
|
+
- **`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`.
|
|
58
|
+
- **A booking keeps its general reversal** (`IExportBooking.generalumkehr`, from field 118) and its cost centres (`kost1`, `kost2`, empty where the row states none).
|
|
54
59
|
|
|
55
60
|
```typescript
|
|
56
61
|
import { belegbilder } from '@fin.cx/compatibility';
|
package/ts/00_commitinfo_data.ts
CHANGED
|
@@ -3,6 +3,6 @@
|
|
|
3
3
|
*/
|
|
4
4
|
export const commitinfo = {
|
|
5
5
|
name: '@fin.cx/compatibility',
|
|
6
|
-
version: '
|
|
6
|
+
version: '4.1.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,10 +1,14 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Why an exchange file could not be written:
|
|
3
|
-
* - `invalid_bookings`: a draft the account policy refuses
|
|
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);
|
|
4
5
|
* - `export_failed`: the conversion into rows failed;
|
|
5
|
-
* - `invalid_documents`: a document of a document-image archive DATEV does not take (its GUID, its format), or none
|
|
6
|
+
* - `invalid_documents`: a document of a document-image archive DATEV does not take (its GUID, its format), or none;
|
|
7
|
+
* - `nothing_to_correct`: a correction Buchungsstapel whose current bookings are the ones handed over;
|
|
8
|
+
* - `handed_over_cost_centres_unknown`: a correction of a period whose bookings handed over include one whose cost
|
|
9
|
+
* centres its record does not state (stored before 4.1) and no rows sent were given; the message names it.
|
|
6
10
|
*/
|
|
7
|
-
export type TCompatibilityErrorCode = 'invalid_bookings' | 'export_failed' | 'invalid_documents';
|
|
11
|
+
export type TCompatibilityErrorCode = 'invalid_bookings' | 'export_failed' | 'invalid_documents' | 'nothing_to_correct' | 'handed_over_cost_centres_unknown';
|
|
8
12
|
|
|
9
13
|
export class CompatibilityError extends Error {
|
|
10
14
|
public readonly code: TCompatibilityErrorCode;
|
package/ts/extf/index.ts
CHANGED
|
@@ -27,6 +27,19 @@ export interface IExportBooking {
|
|
|
27
27
|
text: string;
|
|
28
28
|
/** the document GUID the row links to (field 20, `BEDI "GUID"`) */
|
|
29
29
|
documentGuid?: string;
|
|
30
|
+
/**
|
|
31
|
+
* The cost centres of the row (fields 37 and 38, KOST1 and KOST2), empty where it states none. `bookingsOfRows`
|
|
32
|
+
* records both on every booking; a booking stored before 4.1 has neither, although the row sent stated them: its
|
|
33
|
+
* cost centres are not known. `differingBookingCount` compares it without them; a correction refuses it
|
|
34
|
+
* (`handed_over_cost_centres_unknown`) unless it is given the rows sent (`handedOverRows`).
|
|
35
|
+
*/
|
|
36
|
+
kost1?: string;
|
|
37
|
+
kost2?: string;
|
|
38
|
+
/**
|
|
39
|
+
* The row is a general reversal (field 118 "Generalumkehr", written "1"): it takes back the booking of the same
|
|
40
|
+
* fields on DATEV's side. Absent on an ordinary row.
|
|
41
|
+
*/
|
|
42
|
+
generalumkehr?: true;
|
|
30
43
|
}
|
|
31
44
|
|
|
32
45
|
/** The GUID inside a Beleglink value (`BEDI "GUID"` or the bare GUID). */
|
|
@@ -45,34 +58,103 @@ export const bookingsOfRows = (rowsArg: readonly IDatevBuchungsstapelRow[]): IEx
|
|
|
45
58
|
...(rowArg.belegfeld2 ? { belegfeld2: rowArg.belegfeld2 } : {}),
|
|
46
59
|
text: rowArg.buchungstext,
|
|
47
60
|
...(rowArg.belegLink ? { documentGuid: guidOfLink(rowArg.belegLink) } : {}),
|
|
61
|
+
// recorded on every booking, empty where the row states none: a booking without them was stored before 4.1
|
|
62
|
+
kost1: rowArg.kost1 ?? '',
|
|
63
|
+
kost2: rowArg.kost2 ?? '',
|
|
64
|
+
...(rowArg.generalumkehr === true ? { generalumkehr: true as const } : {}),
|
|
48
65
|
}));
|
|
49
66
|
|
|
67
|
+
/**
|
|
68
|
+
* What a booking says, as two Stapel of one period are compared, apart from its cost centres: its day, amount, side,
|
|
69
|
+
* accounts, BU key, Belegfeld 1 and whether it is a general reversal, not its wording or document link. A reversal
|
|
70
|
+
* never matches an ordinary row.
|
|
71
|
+
*/
|
|
72
|
+
const baseKeyOf = (bookingArg: IExportBooking): string =>
|
|
73
|
+
JSON.stringify([
|
|
74
|
+
bookingArg.date,
|
|
75
|
+
bookingArg.umsatzCents,
|
|
76
|
+
bookingArg.sollHaben,
|
|
77
|
+
bookingArg.konto,
|
|
78
|
+
bookingArg.gegenkonto,
|
|
79
|
+
bookingArg.buKey,
|
|
80
|
+
bookingArg.belegfeld1 ?? '',
|
|
81
|
+
bookingArg.generalumkehr ? 'GU' : '',
|
|
82
|
+
]);
|
|
83
|
+
|
|
84
|
+
/** Whether a booking records its cost centres: every booking read from rows since 4.1 does, one stored before does not. */
|
|
85
|
+
const recordsCostCentres = (bookingArg: IExportBooking): boolean => bookingArg.kost1 !== undefined || bookingArg.kost2 !== undefined;
|
|
86
|
+
|
|
87
|
+
/** What a booking that records its cost centres says, the cost centres included. */
|
|
88
|
+
const fullKeyOf = (bookingArg: IExportBooking): string => JSON.stringify([baseKeyOf(bookingArg), bookingArg.kost1 ?? '', bookingArg.kost2 ?? '']);
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Pairs the bookings of two Stapel of one period that say the same, as a multiset: two bookings that record their
|
|
92
|
+
* cost centres pair on every key field, the cost centres included, so a changed cost centre is a changed booking. A
|
|
93
|
+
* booking that does not record them (stored before 4.1, although the row sent stated them) pairs with any booking of
|
|
94
|
+
* the same other key fields: its record says nothing of them, so they never make it differ. Unpaired recorded bookings take the
|
|
95
|
+
* unrecorded ones of the other side first, which pair with anything, so as many pairs as possible are made.
|
|
96
|
+
*/
|
|
97
|
+
const pairBookings = (
|
|
98
|
+
leftArg: readonly IExportBooking[],
|
|
99
|
+
rightArg: readonly IExportBooking[],
|
|
100
|
+
): { leftPaired: boolean[]; rightPaired: boolean[] } => {
|
|
101
|
+
const leftPaired = leftArg.map(() => false);
|
|
102
|
+
const rightPaired = rightArg.map(() => false);
|
|
103
|
+
const take = (queuesArg: Map<string, number[]>, keyArg: string): number | undefined => queuesArg.get(keyArg)?.shift();
|
|
104
|
+
const queue = (queuesArg: Map<string, number[]>, keyArg: string, indexArg: number): void => {
|
|
105
|
+
queuesArg.set(keyArg, [...(queuesArg.get(keyArg) ?? []), indexArg]);
|
|
106
|
+
};
|
|
107
|
+
// recorded with recorded, on every key field
|
|
108
|
+
const recordedRight = new Map<string, number[]>();
|
|
109
|
+
rightArg.forEach((bookingArg, indexArg) => {
|
|
110
|
+
if (recordsCostCentres(bookingArg)) {
|
|
111
|
+
queue(recordedRight, fullKeyOf(bookingArg), indexArg);
|
|
112
|
+
}
|
|
113
|
+
});
|
|
114
|
+
leftArg.forEach((bookingArg, indexArg) => {
|
|
115
|
+
const paired = recordsCostCentres(bookingArg) ? take(recordedRight, fullKeyOf(bookingArg)) : undefined;
|
|
116
|
+
if (paired !== undefined) {
|
|
117
|
+
leftPaired[indexArg] = true;
|
|
118
|
+
rightPaired[paired] = true;
|
|
119
|
+
}
|
|
120
|
+
});
|
|
121
|
+
// what is left, on the key fields without the cost centres, where one of the two does not record them
|
|
122
|
+
const unrecordedRight = new Map<string, number[]>();
|
|
123
|
+
const openRecordedRight = new Map<string, number[]>();
|
|
124
|
+
rightArg.forEach((bookingArg, indexArg) => {
|
|
125
|
+
if (!rightPaired[indexArg]) {
|
|
126
|
+
queue(recordsCostCentres(bookingArg) ? openRecordedRight : unrecordedRight, baseKeyOf(bookingArg), indexArg);
|
|
127
|
+
}
|
|
128
|
+
});
|
|
129
|
+
const pairLeft = (recordedArg: boolean): void => {
|
|
130
|
+
leftArg.forEach((bookingArg, indexArg) => {
|
|
131
|
+
if (leftPaired[indexArg] || recordsCostCentres(bookingArg) !== recordedArg) {
|
|
132
|
+
return;
|
|
133
|
+
}
|
|
134
|
+
const key = baseKeyOf(bookingArg);
|
|
135
|
+
const paired = recordedArg ? take(unrecordedRight, key) : take(openRecordedRight, key) ?? take(unrecordedRight, key);
|
|
136
|
+
if (paired !== undefined) {
|
|
137
|
+
leftPaired[indexArg] = true;
|
|
138
|
+
rightPaired[paired] = true;
|
|
139
|
+
}
|
|
140
|
+
});
|
|
141
|
+
};
|
|
142
|
+
pairLeft(true);
|
|
143
|
+
pairLeft(false);
|
|
144
|
+
return { leftPaired, rightPaired };
|
|
145
|
+
};
|
|
146
|
+
|
|
50
147
|
/**
|
|
51
148
|
* How many rows two Buchungsstapel of one period do not share, compared on
|
|
52
|
-
* what a booking says (its day, amount, side, accounts, BU key
|
|
53
|
-
*
|
|
54
|
-
* multiset: a row that stands twice in one and once in the other differs once.
|
|
149
|
+
* what a booking says (its day, amount, side, accounts, BU key, Belegfeld 1,
|
|
150
|
+
* 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.
|
|
55
154
|
*/
|
|
56
155
|
export const differingBookingCount = (leftArg: readonly IExportBooking[], rightArg: readonly IExportBooking[]): number => {
|
|
57
|
-
const
|
|
58
|
-
|
|
59
|
-
const unmatched = new Map<string, number>();
|
|
60
|
-
for (const booking of leftArg) {
|
|
61
|
-
unmatched.set(keyOf(booking), (unmatched.get(keyOf(booking)) ?? 0) + 1);
|
|
62
|
-
}
|
|
63
|
-
let differing = 0;
|
|
64
|
-
for (const booking of rightArg) {
|
|
65
|
-
const left = unmatched.get(keyOf(booking)) ?? 0;
|
|
66
|
-
if (left > 0) {
|
|
67
|
-
unmatched.set(keyOf(booking), left - 1);
|
|
68
|
-
} else {
|
|
69
|
-
differing += 1;
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
for (const left of unmatched.values()) {
|
|
73
|
-
differing += left;
|
|
74
|
-
}
|
|
75
|
-
return differing;
|
|
156
|
+
const { leftPaired, rightPaired } = pairBookings(leftArg, rightArg);
|
|
157
|
+
return [...leftPaired, ...rightPaired].filter((pairedArg) => !pairedArg).length;
|
|
76
158
|
};
|
|
77
159
|
|
|
78
160
|
/**
|
|
@@ -182,10 +264,9 @@ export interface IBuchungsstapelFile {
|
|
|
182
264
|
replacedCharacters: IBuchungsstapelReplacement[];
|
|
183
265
|
}
|
|
184
266
|
|
|
185
|
-
/**
|
|
186
|
-
|
|
187
|
-
const
|
|
188
|
-
const { csv } = plugins.skrCore.writeExtfBuchungsstapel(rows, optionsArg.header);
|
|
267
|
+
/** The file of rows: the header and the caption row, the rows, encoded in Windows-1252, with where each character stands. */
|
|
268
|
+
const fileOfRows = (rows: IDatevBuchungsstapelRow[], headerArg: IDatevExtfHeaderOptions, filenameArg: string): IBuchungsstapelFile => {
|
|
269
|
+
const { csv } = plugins.skrCore.writeExtfBuchungsstapel(rows, headerArg);
|
|
189
270
|
const { bytes, replaced } = encodeWindows1252(csv);
|
|
190
271
|
// the file is the header line, the caption line and one line per row, each ending in CRLF (`writeExtfBuchungsstapel`)
|
|
191
272
|
const rowLines = rows.map((rowArg) => plugins.skrCore.datevRowFields(rowArg));
|
|
@@ -210,5 +291,141 @@ export const writeBuchungsstapel = (optionsArg: IBuchungsstapelOptions): IBuchun
|
|
|
210
291
|
}
|
|
211
292
|
return { ...replacedArg, row, field: fieldAt(fieldStartsOf(rowLines[row]), replacedArg.offset - lineStarts[row]) };
|
|
212
293
|
});
|
|
213
|
-
return { filename:
|
|
294
|
+
return { filename: filenameArg, csv, bytes, rows, bookings: bookingsOfRows(rows), replacedCharacters };
|
|
295
|
+
};
|
|
296
|
+
|
|
297
|
+
/** Writes a Buchungsstapel: the rows of the drafts, the header and the caption row, encoded in Windows-1252. */
|
|
298
|
+
export const writeBuchungsstapel = (optionsArg: IBuchungsstapelOptions): IBuchungsstapelFile =>
|
|
299
|
+
fileOfRows(datevRowsOf(optionsArg.drafts, optionsArg.policy), optionsArg.header, optionsArg.filename);
|
|
300
|
+
|
|
301
|
+
/**
|
|
302
|
+
* The row a booking handed over was written as, for a general reversal of it: every field the booking keeps
|
|
303
|
+
* (`IExportBooking`) in its place, the Belegdatum at midnight UTC as the writer reads it.
|
|
304
|
+
*/
|
|
305
|
+
export const rowOfBooking = (bookingArg: IExportBooking): IDatevBuchungsstapelRow => ({
|
|
306
|
+
umsatzCents: bookingArg.umsatzCents,
|
|
307
|
+
sollHaben: bookingArg.sollHaben,
|
|
308
|
+
konto: bookingArg.konto,
|
|
309
|
+
gegenKonto: bookingArg.gegenkonto,
|
|
310
|
+
buSchluessel: bookingArg.buKey as IDatevBuchungsstapelRow['buSchluessel'],
|
|
311
|
+
belegDatum: new Date(`${bookingArg.date}T00:00:00.000Z`),
|
|
312
|
+
...(bookingArg.belegfeld1 ? { belegfeld1: bookingArg.belegfeld1 } : {}),
|
|
313
|
+
...(bookingArg.belegfeld2 ? { belegfeld2: bookingArg.belegfeld2 } : {}),
|
|
314
|
+
buchungstext: bookingArg.text,
|
|
315
|
+
...(bookingArg.documentGuid ? { belegLink: bookingArg.documentGuid } : {}),
|
|
316
|
+
...(bookingArg.kost1 ? { kost1: bookingArg.kost1 } : {}),
|
|
317
|
+
...(bookingArg.kost2 ? { kost2: bookingArg.kost2 } : {}),
|
|
318
|
+
festschreibung: false,
|
|
319
|
+
...(bookingArg.generalumkehr ? { generalumkehr: true } : {}),
|
|
320
|
+
});
|
|
321
|
+
|
|
322
|
+
/** A booking as a refusal names it: its place among the bookings handed over, day, amount, side, accounts and Belegfeld 1. */
|
|
323
|
+
const bookingNameOf = (bookingArg: IExportBooking, indexArg: number): string =>
|
|
324
|
+
`booking ${indexArg + 1} (${bookingArg.date}, ${bookingArg.umsatzCents} ${bookingArg.sollHaben} ${bookingArg.konto}/${bookingArg.gegenkonto}`
|
|
325
|
+
+ `${bookingArg.belegfeld1 ? `, Belegfeld 1 ${bookingArg.belegfeld1}` : ''})`;
|
|
326
|
+
|
|
327
|
+
/**
|
|
328
|
+
* Refuses a state handed over that holds a booking whose cost centres its record does not state (stored before 4.1).
|
|
329
|
+
* The Stapel sent stated them (fields 37 and 38), so DATEV holds them: whether the booking must be taken back turns on
|
|
330
|
+
* them, and a reversal that does not state them would leave them standing in DATEV's cost accounting. The rows sent
|
|
331
|
+
* tell them (`handedOverRows`).
|
|
332
|
+
*/
|
|
333
|
+
const refuseCostCentresUnknown = (handedOverArg: readonly IExportBooking[]): void => {
|
|
334
|
+
const unknown = handedOverArg.findIndex((bookingArg) => !recordsCostCentres(bookingArg));
|
|
335
|
+
if (unknown >= 0) {
|
|
336
|
+
throw new CompatibilityError(
|
|
337
|
+
'handed_over_cost_centres_unknown',
|
|
338
|
+
`${bookingNameOf(handedOverArg[unknown], unknown)} was stored without the cost centres it was sent with; pass the rows of the Stapel sent (handedOverRows)`,
|
|
339
|
+
);
|
|
340
|
+
}
|
|
341
|
+
};
|
|
342
|
+
|
|
343
|
+
/**
|
|
344
|
+
* What a correction of a period handed over changes, compared as `differingBookingCount` compares: the bookings
|
|
345
|
+
* handed over that the current ones no longer hold (`reversed`, each once for each time it is missing), the ones they
|
|
346
|
+
* still hold (`kept`, as they were handed over) and the current rows the bookings handed over do not hold (`added`),
|
|
347
|
+
* 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.
|
|
350
|
+
*/
|
|
351
|
+
export const correctionOf = (
|
|
352
|
+
handedOverArg: readonly IExportBooking[],
|
|
353
|
+
currentArg: readonly IDatevBuchungsstapelRow[],
|
|
354
|
+
): { reversed: IExportBooking[]; kept: IExportBooking[]; added: IDatevBuchungsstapelRow[] } => {
|
|
355
|
+
refuseCostCentresUnknown(handedOverArg);
|
|
356
|
+
const { leftPaired, rightPaired } = pairBookings(handedOverArg, bookingsOfRows(currentArg));
|
|
357
|
+
return {
|
|
358
|
+
reversed: handedOverArg.filter((_bookingArg, indexArg) => !leftPaired[indexArg]),
|
|
359
|
+
kept: handedOverArg.filter((_bookingArg, indexArg) => leftPaired[indexArg]),
|
|
360
|
+
added: currentArg.filter((_rowArg, indexArg) => !rightPaired[indexArg]),
|
|
361
|
+
};
|
|
362
|
+
};
|
|
363
|
+
|
|
364
|
+
/**
|
|
365
|
+
* The state of a period handed over, given once: the bookings stored of it (`handedOver`) or the rows of the Stapel
|
|
366
|
+
* sent (`handedOverRows`). A general reversal in it is refused: the state handed over is compared, not a correction
|
|
367
|
+
* file.
|
|
368
|
+
*/
|
|
369
|
+
export interface ICorrectionBuchungsstapelOptions {
|
|
370
|
+
/**
|
|
371
|
+
* The bookings of the period as they were handed over, as a whole: the bookings of its Buchungsstapel as stored
|
|
372
|
+
* (`IBuchungsstapelFile.bookings`), or after a correction the period's bookings as that correction left them
|
|
373
|
+
* (`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.
|
|
375
|
+
*/
|
|
376
|
+
handedOver?: readonly IExportBooking[];
|
|
377
|
+
/**
|
|
378
|
+
* 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.
|
|
382
|
+
*/
|
|
383
|
+
handedOverRows?: readonly IDatevBuchungsstapelRow[];
|
|
384
|
+
/** the period's drafts as they stand now */
|
|
385
|
+
drafts: readonly plugins.skrCore.IJournalDraft[];
|
|
386
|
+
/** the policy the drafts are checked against */
|
|
387
|
+
policy: plugins.skrCore.IAccountPolicy;
|
|
388
|
+
/** the header of the file: the same period (`dateFrom`, `dateTo`) as the Stapel handed over, a label of its own */
|
|
389
|
+
header: IDatevExtfHeaderOptions;
|
|
390
|
+
filename: string;
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
export interface ICorrectionBuchungsstapelFile extends IBuchungsstapelFile {
|
|
394
|
+
/** the bookings handed over it takes back, each written as a general reversal */
|
|
395
|
+
reversed: IExportBooking[];
|
|
396
|
+
/** the rows it books anew */
|
|
397
|
+
added: IDatevBuchungsstapelRow[];
|
|
398
|
+
/**
|
|
399
|
+
* The period's bookings as DATEV holds them after this correction: each booking handed over that it keeps, as it
|
|
400
|
+
* was handed over (its text and document link too), then the rows it books anew. What the next correction is
|
|
401
|
+
* compared against.
|
|
402
|
+
*/
|
|
403
|
+
bookingsAfter: IExportBooking[];
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
/**
|
|
407
|
+
* Writes the correction Buchungsstapel of a period handed over whose bookings changed since: only what changed. Each
|
|
408
|
+
* booking handed over that the drafts no longer hold is written again with field 118 "Generalumkehr" set, so DATEV
|
|
409
|
+
* takes it back on its side and day, and each row the drafts hold that was not handed over is written as it is; rows
|
|
410
|
+
* in both are not written. Every row keeps its Belegdatum, so it counts in the period it belongs to. A booking handed
|
|
411
|
+
* over is never changed or replaced (§ 146 Abs. 4 AO): it is taken back and booked anew. Throws `nothing_to_correct`
|
|
412
|
+
* when nothing changed; `invalid_bookings` for a general reversal in the state handed over, or for a state given
|
|
413
|
+
* twice or not at all; `handed_over_cost_centres_unknown` for a booking whose cost centres are not known.
|
|
414
|
+
*/
|
|
415
|
+
export const writeCorrectionBuchungsstapel = (optionsArg: ICorrectionBuchungsstapelOptions): ICorrectionBuchungsstapelFile => {
|
|
416
|
+
const handedOver = optionsArg.handedOverRows !== undefined ? bookingsOfRows(optionsArg.handedOverRows) : optionsArg.handedOver;
|
|
417
|
+
if (handedOver === undefined || (optionsArg.handedOver !== undefined && optionsArg.handedOverRows !== undefined)) {
|
|
418
|
+
throw new CompatibilityError('invalid_bookings', 'pass the state handed over once: the bookings stored (handedOver) or the rows sent (handedOverRows)');
|
|
419
|
+
}
|
|
420
|
+
const reversal = handedOver.findIndex((bookingArg) => bookingArg.generalumkehr === true);
|
|
421
|
+
if (reversal >= 0) {
|
|
422
|
+
throw new CompatibilityError('invalid_bookings', `the state handed over holds a general reversal (booking ${reversal + 1}); pass the period's bookings as they stood, not a correction file`);
|
|
423
|
+
}
|
|
424
|
+
const current = datevRowsOf(optionsArg.drafts, optionsArg.policy);
|
|
425
|
+
const { reversed, kept, added } = correctionOf(handedOver, current);
|
|
426
|
+
if (reversed.length === 0 && added.length === 0) {
|
|
427
|
+
throw new CompatibilityError('nothing_to_correct', 'the bookings of the period are the ones handed over; there is nothing to correct');
|
|
428
|
+
}
|
|
429
|
+
const rows = [...reversed.map((bookingArg) => ({ ...rowOfBooking(bookingArg), generalumkehr: true })), ...added];
|
|
430
|
+
return { ...fileOfRows(rows, optionsArg.header, optionsArg.filename), reversed, added, bookingsAfter: [...kept, ...bookingsOfRows(added)] };
|
|
214
431
|
};
|