@fin.cx/skr 1.1.0 → 1.2.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.
Files changed (46) hide show
  1. package/dist_ts/index.d.ts +6 -0
  2. package/dist_ts/index.js +7 -1
  3. package/dist_ts/plugins.d.ts +8 -1
  4. package/dist_ts/plugins.js +10 -2
  5. package/dist_ts/skr.api.d.ts +70 -0
  6. package/dist_ts/skr.api.js +348 -1
  7. package/dist_ts/skr.export.accounts.d.ts +53 -0
  8. package/dist_ts/skr.export.accounts.js +111 -0
  9. package/dist_ts/skr.export.balances.d.ts +59 -0
  10. package/dist_ts/skr.export.balances.js +205 -0
  11. package/dist_ts/skr.export.d.ts +110 -0
  12. package/dist_ts/skr.export.js +315 -0
  13. package/dist_ts/skr.export.ledger.d.ts +95 -0
  14. package/dist_ts/skr.export.ledger.js +164 -0
  15. package/dist_ts/skr.export.pdf.d.ts +82 -0
  16. package/dist_ts/skr.export.pdf.js +548 -0
  17. package/dist_ts/skr.invoice.adapter.d.ts +98 -0
  18. package/dist_ts/skr.invoice.adapter.js +476 -0
  19. package/dist_ts/skr.invoice.booking.d.ts +102 -0
  20. package/dist_ts/skr.invoice.booking.js +556 -0
  21. package/dist_ts/skr.invoice.entity.d.ts +287 -0
  22. package/dist_ts/skr.invoice.entity.js +2 -0
  23. package/dist_ts/skr.invoice.mapper.d.ts +69 -0
  24. package/dist_ts/skr.invoice.mapper.js +401 -0
  25. package/dist_ts/skr.invoice.storage.d.ts +140 -0
  26. package/dist_ts/skr.invoice.storage.js +529 -0
  27. package/dist_ts/skr.security.d.ts +65 -0
  28. package/dist_ts/skr.security.js +319 -0
  29. package/dist_ts/skr.types.d.ts +1 -0
  30. package/package.json +17 -12
  31. package/readme.md +207 -16
  32. package/ts/index.ts +6 -0
  33. package/ts/plugins.ts +22 -1
  34. package/ts/skr.api.ts +485 -0
  35. package/ts/skr.export.accounts.ts +154 -0
  36. package/ts/skr.export.balances.ts +270 -0
  37. package/ts/skr.export.ledger.ts +249 -0
  38. package/ts/skr.export.pdf.ts +601 -0
  39. package/ts/skr.export.ts +443 -0
  40. package/ts/skr.invoice.adapter.ts +581 -0
  41. package/ts/skr.invoice.booking.ts +738 -0
  42. package/ts/skr.invoice.entity.ts +351 -0
  43. package/ts/skr.invoice.mapper.ts +486 -0
  44. package/ts/skr.invoice.storage.ts +710 -0
  45. package/ts/skr.security.ts +405 -0
  46. package/ts/skr.types.ts +1 -0
@@ -0,0 +1,315 @@
1
+ import * as plugins from './plugins.js';
2
+ import * as path from 'path';
3
+ export class SkrExport {
4
+ constructor(options) {
5
+ this.manifest = {};
6
+ this.tagManifest = {};
7
+ this.options = options;
8
+ this.logger = new plugins.smartlog.ConsoleLog();
9
+ this.exportDir = path.join(options.exportPath, `jahresabschluss_${options.fiscalYear}`);
10
+ }
11
+ /**
12
+ * Creates the BagIt directory structure for the export
13
+ */
14
+ async createBagItStructure() {
15
+ this.logger.log('info', 'Creating BagIt directory structure...');
16
+ // Create main directories
17
+ await plugins.smartfile.fs.ensureDir(this.exportDir);
18
+ await plugins.smartfile.fs.ensureDir(path.join(this.exportDir, 'data'));
19
+ await plugins.smartfile.fs.ensureDir(path.join(this.exportDir, 'data', 'metadata'));
20
+ await plugins.smartfile.fs.ensureDir(path.join(this.exportDir, 'data', 'metadata', 'schemas'));
21
+ await plugins.smartfile.fs.ensureDir(path.join(this.exportDir, 'data', 'metadata', 'schemas', 'v1'));
22
+ await plugins.smartfile.fs.ensureDir(path.join(this.exportDir, 'data', 'metadata', 'signatures'));
23
+ await plugins.smartfile.fs.ensureDir(path.join(this.exportDir, 'data', 'accounting'));
24
+ await plugins.smartfile.fs.ensureDir(path.join(this.exportDir, 'data', 'accounting', 'ebilanz'));
25
+ await plugins.smartfile.fs.ensureDir(path.join(this.exportDir, 'data', 'documents'));
26
+ await plugins.smartfile.fs.ensureDir(path.join(this.exportDir, 'data', 'documents', 'by-hash'));
27
+ await plugins.smartfile.fs.ensureDir(path.join(this.exportDir, 'data', 'reports'));
28
+ // Create BagIt declaration file
29
+ await this.createBagItDeclaration();
30
+ // Create README
31
+ await this.createReadme();
32
+ this.logger.log('ok', 'BagIt structure created successfully');
33
+ }
34
+ /**
35
+ * Creates the bagit.txt declaration file
36
+ */
37
+ async createBagItDeclaration() {
38
+ const bagitContent = `BagIt-Version: 1.0
39
+ Tag-File-Character-Encoding: UTF-8`;
40
+ const filePath = path.join(this.exportDir, 'bagit.txt');
41
+ await plugins.smartfile.memory.toFs(bagitContent, filePath);
42
+ // Add to tag manifest
43
+ const hash = await this.hashFile(filePath);
44
+ this.tagManifest['bagit.txt'] = hash;
45
+ }
46
+ /**
47
+ * Creates the README.txt file with Verfahrensdokumentation
48
+ */
49
+ async createReadme() {
50
+ const readmeContent = `SKR Jahresabschluss Export - Verfahrensdokumentation
51
+ =====================================================
52
+
53
+ Dieses Archiv enthält einen revisionssicheren Export des Jahresabschlusses
54
+ gemäß den Grundsätzen ordnungsmäßiger Buchführung (GoBD).
55
+
56
+ Export-Datum: ${new Date().toISOString()}
57
+ Geschäftsjahr: ${this.options.fiscalYear}
58
+ Zeitraum: ${this.options.dateFrom.toISOString()} bis ${this.options.dateTo.toISOString()}
59
+
60
+ STRUKTUR DES ARCHIVS
61
+ --------------------
62
+ - /data/accounting/: Buchhaltungsdaten (Journale, Konten, Salden)
63
+ - /data/documents/: Belegdokumente (content-adressiert)
64
+ - /data/reports/: Finanzberichte (PDF/A-3)
65
+ - /data/metadata/: Export-Metadaten und Schemas
66
+ - /data/metadata/signatures/: Digitale Signaturen und Zeitstempel
67
+
68
+ INTEGRITÄTSSICHERUNG
69
+ --------------------
70
+ - Alle Dateien sind mit SHA-256 gehasht (siehe manifest-sha256.txt)
71
+ - Optional: Digitale Signatur (CAdES) über Manifest
72
+ - Optional: RFC 3161 Zeitstempel
73
+
74
+ AUFBEWAHRUNG
75
+ ------------
76
+ Dieses Archiv muss gemäß § 147 AO für 10 Jahre revisionssicher aufbewahrt werden.
77
+ Empfohlen wird die Speicherung auf WORM-Medien.
78
+
79
+ REIMPORT
80
+ --------
81
+ Das Archiv kann mit der SKR-Software vollständig reimportiert werden.
82
+ Die Datenintegrität wird beim Import automatisch verifiziert.
83
+
84
+ COMPLIANCE
85
+ ----------
86
+ - GoBD-konform
87
+ - E-Bilanz-fähig (XBRL)
88
+ - ZUGFeRD/Factur-X kompatibel
89
+ - PDF/A-3 für Langzeitarchivierung
90
+
91
+ © ${new Date().getFullYear()} ${this.options.companyInfo?.name || 'Export System'}`;
92
+ const filePath = path.join(this.exportDir, 'readme.txt');
93
+ await plugins.smartfile.memory.toFs(readmeContent, filePath);
94
+ // Add to tag manifest
95
+ const hash = await this.hashFile(filePath);
96
+ this.tagManifest['readme.txt'] = hash;
97
+ }
98
+ /**
99
+ * Creates the export metadata JSON file
100
+ */
101
+ async createExportMetadata(skrType) {
102
+ const metadata = {
103
+ exportVersion: '1.0.0',
104
+ exportTimestamp: new Date().toISOString(),
105
+ generator: {
106
+ name: '@fin.cx/skr',
107
+ version: '1.1.0' // Should be read from package.json
108
+ },
109
+ company: this.options.companyInfo,
110
+ fiscalYear: this.options.fiscalYear,
111
+ dateRange: {
112
+ from: this.options.dateFrom.toISOString(),
113
+ to: this.options.dateTo.toISOString()
114
+ },
115
+ skrType: skrType,
116
+ schemaVersion: '1.0',
117
+ crypto: {
118
+ digestAlgorithms: ['sha256'],
119
+ signatureType: this.options.signExport ? 'CAdES' : undefined,
120
+ timestampPolicy: this.options.timestampExport ? 'RFC3161' : undefined,
121
+ merkleTree: true
122
+ },
123
+ options: {
124
+ packagedAs: 'bagit',
125
+ compression: 'none',
126
+ deduplication: true
127
+ }
128
+ };
129
+ const filePath = path.join(this.exportDir, 'data', 'metadata', 'export.json');
130
+ await plugins.smartfile.memory.toFs(JSON.stringify(metadata, null, 2), filePath);
131
+ // Add to manifest
132
+ const hash = await this.hashFile(filePath);
133
+ this.manifest['data/metadata/export.json'] = hash;
134
+ }
135
+ /**
136
+ * Creates JSON schemas for the export data structures
137
+ */
138
+ async createSchemas() {
139
+ // Ledger schema
140
+ const ledgerSchema = {
141
+ "$schema": "http://json-schema.org/draft-07/schema#",
142
+ "title": "Ledger Entry",
143
+ "type": "object",
144
+ "properties": {
145
+ "schema_version": { "type": "string" },
146
+ "entry_id": { "type": "string", "format": "uuid" },
147
+ "booking_date": { "type": "string", "format": "date" },
148
+ "posting_date": { "type": "string", "format": "date" },
149
+ "currency": { "type": "string" },
150
+ "journal": { "type": "string" },
151
+ "description": { "type": "string" },
152
+ "lines": {
153
+ "type": "array",
154
+ "items": {
155
+ "type": "object",
156
+ "properties": {
157
+ "posting_id": { "type": "string" },
158
+ "account_code": { "type": "string" },
159
+ "debit": { "type": "string" },
160
+ "credit": { "type": "string" },
161
+ "tax_code": { "type": "string" },
162
+ "document_refs": {
163
+ "type": "array",
164
+ "items": {
165
+ "type": "object",
166
+ "properties": {
167
+ "content_hash": { "type": "string" },
168
+ "doc_role": { "type": "string" },
169
+ "mime": { "type": "string" }
170
+ }
171
+ }
172
+ }
173
+ },
174
+ "required": ["posting_id", "account_code", "debit", "credit"]
175
+ }
176
+ },
177
+ "created_at": { "type": "string", "format": "date-time" },
178
+ "user": { "type": "string" }
179
+ },
180
+ "required": ["schema_version", "entry_id", "booking_date", "lines"]
181
+ };
182
+ // Accounts schema
183
+ const accountsSchema = {
184
+ "$schema": "http://json-schema.org/draft-07/schema#",
185
+ "title": "Accounts CSV",
186
+ "type": "object",
187
+ "properties": {
188
+ "account_code": { "type": "string" },
189
+ "name": { "type": "string" },
190
+ "type": { "type": "string" },
191
+ "parent": { "type": "string" },
192
+ "skr_set": { "type": "string" },
193
+ "tax_code_default": { "type": "string" },
194
+ "active_from": { "type": "string", "format": "date" },
195
+ "active_to": { "type": "string", "format": "date" }
196
+ },
197
+ "required": ["account_code", "name", "type", "skr_set"]
198
+ };
199
+ // Save schemas
200
+ const schemasDir = path.join(this.exportDir, 'data', 'metadata', 'schemas', 'v1');
201
+ await plugins.smartfile.memory.toFs(JSON.stringify(ledgerSchema, null, 2), path.join(schemasDir, 'ledger.schema.json'));
202
+ this.manifest['data/metadata/schemas/v1/ledger.schema.json'] = await this.hashFile(path.join(schemasDir, 'ledger.schema.json'));
203
+ await plugins.smartfile.memory.toFs(JSON.stringify(accountsSchema, null, 2), path.join(schemasDir, 'accounts.schema.json'));
204
+ this.manifest['data/metadata/schemas/v1/accounts.schema.json'] = await this.hashFile(path.join(schemasDir, 'accounts.schema.json'));
205
+ }
206
+ /**
207
+ * Writes the BagIt manifest files
208
+ */
209
+ async writeManifests() {
210
+ // Write data manifest
211
+ let manifestContent = '';
212
+ for (const [filePath, hash] of Object.entries(this.manifest)) {
213
+ manifestContent += `${hash} ${filePath}\n`;
214
+ }
215
+ const manifestPath = path.join(this.exportDir, 'manifest-sha256.txt');
216
+ await plugins.smartfile.memory.toFs(manifestContent, manifestPath);
217
+ // Add manifest to tag manifest
218
+ this.tagManifest['manifest-sha256.txt'] = await this.hashFile(manifestPath);
219
+ // Write tag manifest
220
+ let tagManifestContent = '';
221
+ for (const [filePath, hash] of Object.entries(this.tagManifest)) {
222
+ tagManifestContent += `${hash} ${filePath}\n`;
223
+ }
224
+ await plugins.smartfile.memory.toFs(tagManifestContent, path.join(this.exportDir, 'tagmanifest-sha256.txt'));
225
+ }
226
+ /**
227
+ * Calculates SHA-256 hash of a file
228
+ */
229
+ async hashFile(filePath) {
230
+ const fileContent = await plugins.smartfile.fs.toBuffer(filePath);
231
+ return await plugins.smarthash.sha256FromBuffer(fileContent);
232
+ }
233
+ /**
234
+ * Stores a document in content-addressed storage
235
+ */
236
+ async storeDocument(content, originalFilename) {
237
+ const hash = await plugins.smarthash.sha256FromBuffer(content);
238
+ // Create path based on hash (first 2 chars as directory)
239
+ const hashPrefix = hash.substring(0, 2);
240
+ const hashDir = path.join(this.exportDir, 'data', 'documents', 'by-hash', hashPrefix);
241
+ await plugins.smartfile.fs.ensureDir(hashDir);
242
+ const docPath = path.join(hashDir, hash);
243
+ // Only store if not already exists (deduplication)
244
+ if (!(await plugins.smartfile.fs.fileExists(docPath))) {
245
+ await plugins.smartfile.memory.toFs(content, docPath);
246
+ this.manifest[`data/documents/by-hash/${hashPrefix}/${hash}`] = hash;
247
+ }
248
+ return hash;
249
+ }
250
+ /**
251
+ * Creates a Merkle tree from all file hashes
252
+ */
253
+ async createMerkleTree() {
254
+ const leaves = Object.values(this.manifest).map(hash => Buffer.from(hash, 'hex'));
255
+ // Create a sync hash function wrapper for MerkleTree
256
+ const hashFn = (data) => {
257
+ // Convert async to sync by using crypto directly
258
+ const crypto = require('crypto');
259
+ return crypto.createHash('sha256').update(data).digest();
260
+ };
261
+ const tree = new plugins.MerkleTree(leaves, hashFn, {
262
+ sortPairs: true
263
+ });
264
+ const root = tree.getRoot().toString('hex');
265
+ // Save Merkle tree data
266
+ const merkleData = {
267
+ root: root,
268
+ leaves: Object.entries(this.manifest).map(([path, hash]) => ({
269
+ path,
270
+ hash
271
+ })),
272
+ timestamp: new Date().toISOString()
273
+ };
274
+ const merklePath = path.join(this.exportDir, 'data', 'metadata', 'merkle-tree.json');
275
+ await plugins.smartfile.memory.toFs(JSON.stringify(merkleData, null, 2), merklePath);
276
+ this.manifest['data/metadata/merkle-tree.json'] = await this.hashFile(merklePath);
277
+ return root;
278
+ }
279
+ /**
280
+ * Validates the BagIt structure
281
+ */
282
+ async validateBagIt() {
283
+ this.logger.log('info', 'Validating BagIt structure...');
284
+ // Check required files exist
285
+ const requiredFiles = [
286
+ 'bagit.txt',
287
+ 'manifest-sha256.txt',
288
+ 'tagmanifest-sha256.txt',
289
+ 'readme.txt'
290
+ ];
291
+ for (const file of requiredFiles) {
292
+ const filePath = path.join(this.exportDir, file);
293
+ if (!(await plugins.smartfile.fs.fileExists(filePath))) {
294
+ this.logger.log('error', `Required file missing: ${file}`);
295
+ return false;
296
+ }
297
+ }
298
+ // Verify all manifest entries
299
+ for (const [relPath, expectedHash] of Object.entries(this.manifest)) {
300
+ const fullPath = path.join(this.exportDir, relPath);
301
+ if (!(await plugins.smartfile.fs.fileExists(fullPath))) {
302
+ this.logger.log('error', `Manifest file missing: ${relPath}`);
303
+ return false;
304
+ }
305
+ const actualHash = await this.hashFile(fullPath);
306
+ if (actualHash !== expectedHash) {
307
+ this.logger.log('error', `Hash mismatch for ${relPath}`);
308
+ return false;
309
+ }
310
+ }
311
+ this.logger.log('ok', 'BagIt validation successful');
312
+ return true;
313
+ }
314
+ }
315
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2tyLmV4cG9ydC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3RzL3Nrci5leHBvcnQudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxLQUFLLE9BQU8sTUFBTSxjQUFjLENBQUM7QUFDeEMsT0FBTyxLQUFLLElBQUksTUFBTSxNQUFNLENBQUM7QUFvRTdCLE1BQU0sT0FBTyxTQUFTO0lBT3BCLFlBQVksT0FBdUI7UUFIM0IsYUFBUSxHQUFtQixFQUFFLENBQUM7UUFDOUIsZ0JBQVcsR0FBbUIsRUFBRSxDQUFDO1FBR3ZDLElBQUksQ0FBQyxPQUFPLEdBQUcsT0FBTyxDQUFDO1FBQ3ZCLElBQUksQ0FBQyxNQUFNLEdBQUcsSUFBSSxPQUFPLENBQUMsUUFBUSxDQUFDLFVBQVUsRUFBRSxDQUFDO1FBQ2hELElBQUksQ0FBQyxTQUFTLEdBQUcsSUFBSSxDQUFDLElBQUksQ0FBQyxPQUFPLENBQUMsVUFBVSxFQUFFLG1CQUFtQixPQUFPLENBQUMsVUFBVSxFQUFFLENBQUMsQ0FBQztJQUMxRixDQUFDO0lBRUQ7O09BRUc7SUFDSSxLQUFLLENBQUMsb0JBQW9CO1FBQy9CLElBQUksQ0FBQyxNQUFNLENBQUMsR0FBRyxDQUFDLE1BQU0sRUFBRSx1Q0FBdUMsQ0FBQyxDQUFDO1FBRWpFLDBCQUEwQjtRQUMxQixNQUFNLE9BQU8sQ0FBQyxTQUFTLENBQUMsRUFBRSxDQUFDLFNBQVMsQ0FBQyxJQUFJLENBQUMsU0FBUyxDQUFDLENBQUM7UUFDckQsTUFBTSxPQUFPLENBQUMsU0FBUyxDQUFDLEVBQUUsQ0FBQyxTQUFTLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsU0FBUyxFQUFFLE1BQU0sQ0FBQyxDQUFDLENBQUM7UUFDeEUsTUFBTSxPQUFPLENBQUMsU0FBUyxDQUFDLEVBQUUsQ0FBQyxTQUFTLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsU0FBUyxFQUFFLE1BQU0sRUFBRSxVQUFVLENBQUMsQ0FBQyxDQUFDO1FBQ3BGLE1BQU0sT0FBTyxDQUFDLFNBQVMsQ0FBQyxFQUFFLENBQUMsU0FBUyxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLFNBQVMsRUFBRSxNQUFNLEVBQUUsVUFBVSxFQUFFLFNBQVMsQ0FBQyxDQUFDLENBQUM7UUFDL0YsTUFBTSxPQUFPLENBQUMsU0FBUyxDQUFDLEVBQUUsQ0FBQyxTQUFTLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsU0FBUyxFQUFFLE1BQU0sRUFBRSxVQUFVLEVBQUUsU0FBUyxFQUFFLElBQUksQ0FBQyxDQUFDLENBQUM7UUFDckcsTUFBTSxPQUFPLENBQUMsU0FBUyxDQUFDLEVBQUUsQ0FBQyxTQUFTLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsU0FBUyxFQUFFLE1BQU0sRUFBRSxVQUFVLEVBQUUsWUFBWSxDQUFDLENBQUMsQ0FBQztRQUNsRyxNQUFNLE9BQU8sQ0FBQyxTQUFTLENBQUMsRUFBRSxDQUFDLFNBQVMsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxTQUFTLEVBQUUsTUFBTSxFQUFFLFlBQVksQ0FBQyxDQUFDLENBQUM7UUFDdEYsTUFBTSxPQUFPLENBQUMsU0FBUyxDQUFDLEVBQUUsQ0FBQyxTQUFTLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsU0FBUyxFQUFFLE1BQU0sRUFBRSxZQUFZLEVBQUUsU0FBUyxDQUFDLENBQUMsQ0FBQztRQUNqRyxNQUFNLE9BQU8sQ0FBQyxTQUFTLENBQUMsRUFBRSxDQUFDLFNBQVMsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxTQUFTLEVBQUUsTUFBTSxFQUFFLFdBQVcsQ0FBQyxDQUFDLENBQUM7UUFDckYsTUFBTSxPQUFPLENBQUMsU0FBUyxDQUFDLEVBQUUsQ0FBQyxTQUFTLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsU0FBUyxFQUFFLE1BQU0sRUFBRSxXQUFXLEVBQUUsU0FBUyxD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
@@ -0,0 +1,95 @@
1
+ import type { ITransactionData, IJournalEntry, IJournalEntryLine } from './skr.types.js';
2
+ export interface ITransactionDataExport extends ITransactionData {
3
+ _id?: string;
4
+ postingDate?: Date;
5
+ currency?: string;
6
+ createdAt?: Date | string;
7
+ modifiedAt?: Date | string;
8
+ reversalOf?: string;
9
+ reversedBy?: string;
10
+ taxCode?: string;
11
+ project?: string;
12
+ vatAccount?: string;
13
+ }
14
+ export interface IJournalEntryExport extends IJournalEntry {
15
+ _id?: string;
16
+ postingDate?: Date;
17
+ currency?: string;
18
+ journal?: string;
19
+ createdAt?: Date | string;
20
+ modifiedAt?: Date | string;
21
+ reversalOf?: string;
22
+ reversedBy?: string;
23
+ }
24
+ export interface IJournalEntryLineExport extends IJournalEntryLine {
25
+ taxCode?: string;
26
+ project?: string;
27
+ }
28
+ export interface ILedgerEntry {
29
+ schema_version: string;
30
+ entry_id: string;
31
+ booking_date: string;
32
+ posting_date: string;
33
+ period?: string;
34
+ currency: string;
35
+ journal: string;
36
+ description: string;
37
+ reference?: string;
38
+ lines: ILedgerLine[];
39
+ document_refs?: IDocumentRef[];
40
+ created_at: string;
41
+ modified_at?: string;
42
+ user?: string;
43
+ reversal_of?: string;
44
+ reversed_by?: string;
45
+ }
46
+ export interface ILedgerLine {
47
+ posting_id: string;
48
+ account_code: string;
49
+ debit: string;
50
+ credit: string;
51
+ tax_code?: string;
52
+ cost_center?: string;
53
+ project?: string;
54
+ description?: string;
55
+ }
56
+ export interface IDocumentRef {
57
+ content_hash: string;
58
+ doc_role: 'invoice' | 'receipt' | 'contract' | 'bank-statement' | 'other';
59
+ doc_mime: string;
60
+ doc_original_name?: string;
61
+ }
62
+ export declare class LedgerExporter {
63
+ private exportPath;
64
+ private stream;
65
+ private entryCount;
66
+ constructor(exportPath: string);
67
+ /**
68
+ * Initializes the NDJSON export stream
69
+ */
70
+ initialize(): Promise<void>;
71
+ /**
72
+ * Exports a transaction as a ledger entry
73
+ */
74
+ exportTransaction(transaction: ITransactionDataExport): Promise<void>;
75
+ /**
76
+ * Exports a journal entry
77
+ */
78
+ exportJournalEntry(journalEntry: IJournalEntryExport): Promise<void>;
79
+ /**
80
+ * Writes a single NDJSON line
81
+ */
82
+ private writeLine;
83
+ /**
84
+ * Formats a date to ISO date string
85
+ */
86
+ private formatDate;
87
+ /**
88
+ * Closes the export stream
89
+ */
90
+ close(): Promise<number>;
91
+ /**
92
+ * Gets the number of exported entries
93
+ */
94
+ getEntryCount(): number;
95
+ }
@@ -0,0 +1,164 @@
1
+ import * as plugins from './plugins.js';
2
+ import * as path from 'path';
3
+ import { createWriteStream } from 'fs';
4
+ export class LedgerExporter {
5
+ constructor(exportPath) {
6
+ this.stream = null;
7
+ this.entryCount = 0;
8
+ this.exportPath = exportPath;
9
+ }
10
+ /**
11
+ * Initializes the NDJSON export stream
12
+ */
13
+ async initialize() {
14
+ const ledgerPath = path.join(this.exportPath, 'data', 'accounting', 'ledger.ndjson');
15
+ await plugins.smartfile.fs.ensureDir(path.dirname(ledgerPath));
16
+ this.stream = createWriteStream(ledgerPath, {
17
+ encoding: 'utf8',
18
+ flags: 'w'
19
+ });
20
+ }
21
+ /**
22
+ * Exports a transaction as a ledger entry
23
+ */
24
+ async exportTransaction(transaction) {
25
+ if (!this.stream) {
26
+ throw new Error('Ledger exporter not initialized');
27
+ }
28
+ const entry = {
29
+ schema_version: '1.0',
30
+ entry_id: transaction._id || plugins.smartunique.shortId(),
31
+ booking_date: this.formatDate(transaction.date),
32
+ posting_date: this.formatDate(transaction.postingDate || transaction.date),
33
+ currency: transaction.currency || 'EUR',
34
+ journal: 'GL',
35
+ description: transaction.description,
36
+ reference: transaction.reference,
37
+ lines: [],
38
+ created_at: transaction.createdAt ? new Date(transaction.createdAt).toISOString() : new Date().toISOString(),
39
+ modified_at: transaction.modifiedAt ? new Date(transaction.modifiedAt).toISOString() : undefined,
40
+ reversal_of: transaction.reversalOf,
41
+ reversed_by: transaction.reversedBy
42
+ };
43
+ // Add debit line
44
+ if (transaction.amount > 0) {
45
+ entry.lines.push({
46
+ posting_id: `${entry.entry_id}-1`,
47
+ account_code: transaction.debitAccount,
48
+ debit: transaction.amount.toFixed(2),
49
+ credit: '0.00',
50
+ tax_code: transaction.taxCode,
51
+ cost_center: transaction.costCenter,
52
+ project: transaction.project
53
+ });
54
+ // Add credit line
55
+ entry.lines.push({
56
+ posting_id: `${entry.entry_id}-2`,
57
+ account_code: transaction.creditAccount,
58
+ debit: '0.00',
59
+ credit: transaction.amount.toFixed(2)
60
+ });
61
+ }
62
+ // Add VAT lines if applicable
63
+ if (transaction.vatAmount && transaction.vatAmount > 0) {
64
+ entry.lines.push({
65
+ posting_id: `${entry.entry_id}-3`,
66
+ account_code: transaction.vatAccount || '1576', // Default VAT account
67
+ debit: transaction.vatAmount.toFixed(2),
68
+ credit: '0.00',
69
+ description: 'Vorsteuer'
70
+ });
71
+ }
72
+ await this.writeLine(entry);
73
+ }
74
+ /**
75
+ * Exports a journal entry
76
+ */
77
+ async exportJournalEntry(journalEntry) {
78
+ if (!this.stream) {
79
+ throw new Error('Ledger exporter not initialized');
80
+ }
81
+ const entry = {
82
+ schema_version: '1.0',
83
+ entry_id: journalEntry._id || plugins.smartunique.shortId(),
84
+ booking_date: this.formatDate(journalEntry.date),
85
+ posting_date: this.formatDate(journalEntry.postingDate || journalEntry.date),
86
+ currency: journalEntry.currency || 'EUR',
87
+ journal: journalEntry.journal || 'GL',
88
+ description: journalEntry.description,
89
+ reference: journalEntry.reference,
90
+ lines: [],
91
+ created_at: journalEntry.createdAt ? new Date(journalEntry.createdAt).toISOString() : new Date().toISOString(),
92
+ modified_at: journalEntry.modifiedAt ? new Date(journalEntry.modifiedAt).toISOString() : undefined,
93
+ reversal_of: journalEntry.reversalOf,
94
+ reversed_by: journalEntry.reversedBy
95
+ };
96
+ // Convert journal entry lines
97
+ journalEntry.lines.forEach((line, index) => {
98
+ const extLine = line;
99
+ entry.lines.push({
100
+ posting_id: `${entry.entry_id}-${index + 1}`,
101
+ account_code: line.accountNumber,
102
+ debit: (line.debit || 0).toFixed(2),
103
+ credit: (line.credit || 0).toFixed(2),
104
+ tax_code: extLine.taxCode,
105
+ cost_center: line.costCenter,
106
+ project: extLine.project,
107
+ description: line.description
108
+ });
109
+ });
110
+ await this.writeLine(entry);
111
+ }
112
+ /**
113
+ * Writes a single NDJSON line
114
+ */
115
+ async writeLine(entry) {
116
+ return new Promise((resolve, reject) => {
117
+ if (!this.stream) {
118
+ reject(new Error('Stream not initialized'));
119
+ return;
120
+ }
121
+ const line = JSON.stringify(entry) + '\n';
122
+ this.stream.write(line, (error) => {
123
+ if (error) {
124
+ reject(error);
125
+ }
126
+ else {
127
+ this.entryCount++;
128
+ resolve();
129
+ }
130
+ });
131
+ });
132
+ }
133
+ /**
134
+ * Formats a date to ISO date string
135
+ */
136
+ formatDate(date) {
137
+ if (typeof date === 'string') {
138
+ return date.split('T')[0];
139
+ }
140
+ return date.toISOString().split('T')[0];
141
+ }
142
+ /**
143
+ * Closes the export stream
144
+ */
145
+ async close() {
146
+ return new Promise((resolve) => {
147
+ if (this.stream) {
148
+ this.stream.end(() => {
149
+ resolve(this.entryCount);
150
+ });
151
+ }
152
+ else {
153
+ resolve(this.entryCount);
154
+ }
155
+ });
156
+ }
157
+ /**
158
+ * Gets the number of exported entries
159
+ */
160
+ getEntryCount() {
161
+ return this.entryCount;
162
+ }
163
+ }
164
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2tyLmV4cG9ydC5sZWRnZXIuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi90cy9za3IuZXhwb3J0LmxlZGdlci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEtBQUssT0FBTyxNQUFNLGNBQWMsQ0FBQztBQUN4QyxPQUFPLEtBQUssSUFBSSxNQUFNLE1BQU0sQ0FBQztBQUU3QixPQUFPLEVBQUUsaUJBQWlCLEVBQW9CLE1BQU0sSUFBSSxDQUFDO0FBcUV6RCxNQUFNLE9BQU8sY0FBYztJQUt6QixZQUFZLFVBQWtCO1FBSHRCLFdBQU0sR0FBdUIsSUFBSSxDQUFDO1FBQ2xDLGVBQVUsR0FBVyxDQUFDLENBQUM7UUFHN0IsSUFBSSxDQUFDLFVBQVUsR0FBRyxVQUFVLENBQUM7SUFDL0IsQ0FBQztJQUVEOztPQUVHO0lBQ0ksS0FBSyxDQUFDLFVBQVU7UUFDckIsTUFBTSxVQUFVLEdBQUcsSUFBSSxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsVUFBVSxFQUFFLE1BQU0sRUFBRSxZQUFZLEVBQUUsZUFBZSxDQUFDLENBQUM7UUFDckYsTUFBTSxPQUFPLENBQUMsU0FBUyxDQUFDLEVBQUUsQ0FBQyxTQUFTLENBQUMsSUFBSSxDQUFDLE9BQU8sQ0FBQyxVQUFVLENBQUMsQ0FBQyxDQUFDO1FBRS9ELElBQUksQ0FBQyxNQUFNLEdBQUcsaUJBQWlCLENBQUMsVUFBVSxFQUFFO1lBQzFDLFFBQVEsRUFBRSxNQUFNO1lBQ2hCLEtBQUssRUFBRSxHQUFHO1NBQ1gsQ0FBQyxDQUFDO0lBQ0wsQ0FBQztJQUVEOztPQUVHO0lBQ0ksS0FBSyxDQUFDLGlCQUFpQixDQUFDLFdBQW1DO1FBQ2hFLElBQUksQ0FBQyxJQUFJLENBQUMsTUFBTSxFQUFFLENBQUM7WUFDakIsTUFBTSxJQUFJLEtBQUssQ0FBQyxpQ0FBaUMsQ0FBQyxDQUFDO1FBQ3JELENBQUM7UUFFRCxNQUFNLEtBQUssR0FBaUI7WUFDMUIsY0FBYyxFQUFFLEtBQUs7WUFDckIsUUFB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