@fin.cx/skr 1.0.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.
- package/dist_ts/index.d.ts +6 -0
- package/dist_ts/index.js +7 -1
- package/dist_ts/plugins.d.ts +8 -1
- package/dist_ts/plugins.js +10 -2
- package/dist_ts/skr.api.d.ts +70 -0
- package/dist_ts/skr.api.js +354 -3
- package/dist_ts/skr.classes.journalentry.d.ts +1 -0
- package/dist_ts/skr.classes.journalentry.js +55 -15
- package/dist_ts/skr.classes.ledger.d.ts +4 -0
- package/dist_ts/skr.classes.ledger.js +72 -1
- package/dist_ts/skr.classes.reports.js +56 -22
- package/dist_ts/skr.export.accounts.d.ts +53 -0
- package/dist_ts/skr.export.accounts.js +111 -0
- package/dist_ts/skr.export.balances.d.ts +59 -0
- package/dist_ts/skr.export.balances.js +205 -0
- package/dist_ts/skr.export.d.ts +110 -0
- package/dist_ts/skr.export.js +315 -0
- package/dist_ts/skr.export.ledger.d.ts +95 -0
- package/dist_ts/skr.export.ledger.js +164 -0
- package/dist_ts/skr.export.pdf.d.ts +82 -0
- package/dist_ts/skr.export.pdf.js +548 -0
- package/dist_ts/skr.invoice.adapter.d.ts +98 -0
- package/dist_ts/skr.invoice.adapter.js +476 -0
- package/dist_ts/skr.invoice.booking.d.ts +102 -0
- package/dist_ts/skr.invoice.booking.js +556 -0
- package/dist_ts/skr.invoice.entity.d.ts +287 -0
- package/dist_ts/skr.invoice.entity.js +2 -0
- package/dist_ts/skr.invoice.mapper.d.ts +69 -0
- package/dist_ts/skr.invoice.mapper.js +401 -0
- package/dist_ts/skr.invoice.storage.d.ts +140 -0
- package/dist_ts/skr.invoice.storage.js +529 -0
- package/dist_ts/skr.security.d.ts +65 -0
- package/dist_ts/skr.security.js +319 -0
- package/dist_ts/skr.types.d.ts +1 -0
- package/package.json +18 -12
- package/readme.md +461 -132
- package/ts/index.ts +6 -0
- package/ts/plugins.ts +22 -1
- package/ts/skr.api.ts +489 -2
- package/ts/skr.classes.journalentry.ts +63 -14
- package/ts/skr.classes.ledger.ts +85 -0
- package/ts/skr.classes.reports.ts +64 -21
- package/ts/skr.export.accounts.ts +154 -0
- package/ts/skr.export.balances.ts +270 -0
- package/ts/skr.export.ledger.ts +249 -0
- package/ts/skr.export.pdf.ts +601 -0
- package/ts/skr.export.ts +443 -0
- package/ts/skr.invoice.adapter.ts +581 -0
- package/ts/skr.invoice.booking.ts +738 -0
- package/ts/skr.invoice.entity.ts +351 -0
- package/ts/skr.invoice.mapper.ts +486 -0
- package/ts/skr.invoice.storage.ts +710 -0
- package/ts/skr.security.ts +405 -0
- package/ts/skr.types.ts +1 -0
|
@@ -0,0 +1,249 @@
|
|
|
1
|
+
import * as plugins from './plugins.js';
|
|
2
|
+
import * as path from 'path';
|
|
3
|
+
import type { ITransactionData, IJournalEntry, IJournalEntryLine } from './skr.types.js';
|
|
4
|
+
import { createWriteStream, type WriteStream } from 'fs';
|
|
5
|
+
|
|
6
|
+
// Extended interfaces for export with additional tracking fields
|
|
7
|
+
export interface ITransactionDataExport extends ITransactionData {
|
|
8
|
+
_id?: string;
|
|
9
|
+
postingDate?: Date;
|
|
10
|
+
currency?: string;
|
|
11
|
+
createdAt?: Date | string;
|
|
12
|
+
modifiedAt?: Date | string;
|
|
13
|
+
reversalOf?: string;
|
|
14
|
+
reversedBy?: string;
|
|
15
|
+
taxCode?: string;
|
|
16
|
+
project?: string;
|
|
17
|
+
vatAccount?: string;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export interface IJournalEntryExport extends IJournalEntry {
|
|
21
|
+
_id?: string;
|
|
22
|
+
postingDate?: Date;
|
|
23
|
+
currency?: string;
|
|
24
|
+
journal?: string;
|
|
25
|
+
createdAt?: Date | string;
|
|
26
|
+
modifiedAt?: Date | string;
|
|
27
|
+
reversalOf?: string;
|
|
28
|
+
reversedBy?: string;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export interface IJournalEntryLineExport extends IJournalEntryLine {
|
|
32
|
+
taxCode?: string;
|
|
33
|
+
project?: string;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export interface ILedgerEntry {
|
|
37
|
+
schema_version: string;
|
|
38
|
+
entry_id: string;
|
|
39
|
+
booking_date: string;
|
|
40
|
+
posting_date: string;
|
|
41
|
+
period?: string;
|
|
42
|
+
currency: string;
|
|
43
|
+
journal: string;
|
|
44
|
+
description: string;
|
|
45
|
+
reference?: string;
|
|
46
|
+
lines: ILedgerLine[];
|
|
47
|
+
document_refs?: IDocumentRef[];
|
|
48
|
+
created_at: string;
|
|
49
|
+
modified_at?: string;
|
|
50
|
+
user?: string;
|
|
51
|
+
reversal_of?: string;
|
|
52
|
+
reversed_by?: string;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export interface ILedgerLine {
|
|
56
|
+
posting_id: string;
|
|
57
|
+
account_code: string;
|
|
58
|
+
debit: string;
|
|
59
|
+
credit: string;
|
|
60
|
+
tax_code?: string;
|
|
61
|
+
cost_center?: string;
|
|
62
|
+
project?: string;
|
|
63
|
+
description?: string;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export interface IDocumentRef {
|
|
67
|
+
content_hash: string;
|
|
68
|
+
doc_role: 'invoice' | 'receipt' | 'contract' | 'bank-statement' | 'other';
|
|
69
|
+
doc_mime: string;
|
|
70
|
+
doc_original_name?: string;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export class LedgerExporter {
|
|
74
|
+
private exportPath: string;
|
|
75
|
+
private stream: WriteStream | null = null;
|
|
76
|
+
private entryCount: number = 0;
|
|
77
|
+
|
|
78
|
+
constructor(exportPath: string) {
|
|
79
|
+
this.exportPath = exportPath;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Initializes the NDJSON export stream
|
|
84
|
+
*/
|
|
85
|
+
public async initialize(): Promise<void> {
|
|
86
|
+
const ledgerPath = path.join(this.exportPath, 'data', 'accounting', 'ledger.ndjson');
|
|
87
|
+
await plugins.smartfile.fs.ensureDir(path.dirname(ledgerPath));
|
|
88
|
+
|
|
89
|
+
this.stream = createWriteStream(ledgerPath, {
|
|
90
|
+
encoding: 'utf8',
|
|
91
|
+
flags: 'w'
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Exports a transaction as a ledger entry
|
|
97
|
+
*/
|
|
98
|
+
public async exportTransaction(transaction: ITransactionDataExport): Promise<void> {
|
|
99
|
+
if (!this.stream) {
|
|
100
|
+
throw new Error('Ledger exporter not initialized');
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
const entry: ILedgerEntry = {
|
|
104
|
+
schema_version: '1.0',
|
|
105
|
+
entry_id: transaction._id || plugins.smartunique.shortId(),
|
|
106
|
+
booking_date: this.formatDate(transaction.date),
|
|
107
|
+
posting_date: this.formatDate(transaction.postingDate || transaction.date),
|
|
108
|
+
currency: transaction.currency || 'EUR',
|
|
109
|
+
journal: 'GL',
|
|
110
|
+
description: transaction.description,
|
|
111
|
+
reference: transaction.reference,
|
|
112
|
+
lines: [],
|
|
113
|
+
created_at: transaction.createdAt ? new Date(transaction.createdAt).toISOString() : new Date().toISOString(),
|
|
114
|
+
modified_at: transaction.modifiedAt ? new Date(transaction.modifiedAt).toISOString() : undefined,
|
|
115
|
+
reversal_of: transaction.reversalOf,
|
|
116
|
+
reversed_by: transaction.reversedBy
|
|
117
|
+
};
|
|
118
|
+
|
|
119
|
+
// Add debit line
|
|
120
|
+
if (transaction.amount > 0) {
|
|
121
|
+
entry.lines.push({
|
|
122
|
+
posting_id: `${entry.entry_id}-1`,
|
|
123
|
+
account_code: transaction.debitAccount,
|
|
124
|
+
debit: transaction.amount.toFixed(2),
|
|
125
|
+
credit: '0.00',
|
|
126
|
+
tax_code: transaction.taxCode,
|
|
127
|
+
cost_center: transaction.costCenter,
|
|
128
|
+
project: transaction.project
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
// Add credit line
|
|
132
|
+
entry.lines.push({
|
|
133
|
+
posting_id: `${entry.entry_id}-2`,
|
|
134
|
+
account_code: transaction.creditAccount,
|
|
135
|
+
debit: '0.00',
|
|
136
|
+
credit: transaction.amount.toFixed(2)
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
// Add VAT lines if applicable
|
|
141
|
+
if (transaction.vatAmount && transaction.vatAmount > 0) {
|
|
142
|
+
entry.lines.push({
|
|
143
|
+
posting_id: `${entry.entry_id}-3`,
|
|
144
|
+
account_code: transaction.vatAccount || '1576', // Default VAT account
|
|
145
|
+
debit: transaction.vatAmount.toFixed(2),
|
|
146
|
+
credit: '0.00',
|
|
147
|
+
description: 'Vorsteuer'
|
|
148
|
+
});
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
await this.writeLine(entry);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* Exports a journal entry
|
|
156
|
+
*/
|
|
157
|
+
public async exportJournalEntry(journalEntry: IJournalEntryExport): Promise<void> {
|
|
158
|
+
if (!this.stream) {
|
|
159
|
+
throw new Error('Ledger exporter not initialized');
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
const entry: ILedgerEntry = {
|
|
163
|
+
schema_version: '1.0',
|
|
164
|
+
entry_id: journalEntry._id || plugins.smartunique.shortId(),
|
|
165
|
+
booking_date: this.formatDate(journalEntry.date),
|
|
166
|
+
posting_date: this.formatDate(journalEntry.postingDate || journalEntry.date),
|
|
167
|
+
currency: journalEntry.currency || 'EUR',
|
|
168
|
+
journal: journalEntry.journal || 'GL',
|
|
169
|
+
description: journalEntry.description,
|
|
170
|
+
reference: journalEntry.reference,
|
|
171
|
+
lines: [],
|
|
172
|
+
created_at: journalEntry.createdAt ? new Date(journalEntry.createdAt).toISOString() : new Date().toISOString(),
|
|
173
|
+
modified_at: journalEntry.modifiedAt ? new Date(journalEntry.modifiedAt).toISOString() : undefined,
|
|
174
|
+
reversal_of: journalEntry.reversalOf,
|
|
175
|
+
reversed_by: journalEntry.reversedBy
|
|
176
|
+
};
|
|
177
|
+
|
|
178
|
+
// Convert journal entry lines
|
|
179
|
+
journalEntry.lines.forEach((line, index) => {
|
|
180
|
+
const extLine = line as IJournalEntryLineExport;
|
|
181
|
+
entry.lines.push({
|
|
182
|
+
posting_id: `${entry.entry_id}-${index + 1}`,
|
|
183
|
+
account_code: line.accountNumber,
|
|
184
|
+
debit: (line.debit || 0).toFixed(2),
|
|
185
|
+
credit: (line.credit || 0).toFixed(2),
|
|
186
|
+
tax_code: extLine.taxCode,
|
|
187
|
+
cost_center: line.costCenter,
|
|
188
|
+
project: extLine.project,
|
|
189
|
+
description: line.description
|
|
190
|
+
});
|
|
191
|
+
});
|
|
192
|
+
|
|
193
|
+
await this.writeLine(entry);
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
/**
|
|
197
|
+
* Writes a single NDJSON line
|
|
198
|
+
*/
|
|
199
|
+
private async writeLine(entry: ILedgerEntry): Promise<void> {
|
|
200
|
+
return new Promise((resolve, reject) => {
|
|
201
|
+
if (!this.stream) {
|
|
202
|
+
reject(new Error('Stream not initialized'));
|
|
203
|
+
return;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
const line = JSON.stringify(entry) + '\n';
|
|
207
|
+
this.stream.write(line, (error) => {
|
|
208
|
+
if (error) {
|
|
209
|
+
reject(error);
|
|
210
|
+
} else {
|
|
211
|
+
this.entryCount++;
|
|
212
|
+
resolve();
|
|
213
|
+
}
|
|
214
|
+
});
|
|
215
|
+
});
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
/**
|
|
219
|
+
* Formats a date to ISO date string
|
|
220
|
+
*/
|
|
221
|
+
private formatDate(date: Date | string): string {
|
|
222
|
+
if (typeof date === 'string') {
|
|
223
|
+
return date.split('T')[0];
|
|
224
|
+
}
|
|
225
|
+
return date.toISOString().split('T')[0];
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
/**
|
|
229
|
+
* Closes the export stream
|
|
230
|
+
*/
|
|
231
|
+
public async close(): Promise<number> {
|
|
232
|
+
return new Promise((resolve) => {
|
|
233
|
+
if (this.stream) {
|
|
234
|
+
this.stream.end(() => {
|
|
235
|
+
resolve(this.entryCount);
|
|
236
|
+
});
|
|
237
|
+
} else {
|
|
238
|
+
resolve(this.entryCount);
|
|
239
|
+
}
|
|
240
|
+
});
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
/**
|
|
244
|
+
* Gets the number of exported entries
|
|
245
|
+
*/
|
|
246
|
+
public getEntryCount(): number {
|
|
247
|
+
return this.entryCount;
|
|
248
|
+
}
|
|
249
|
+
}
|