@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.
- 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 +348 -1
- 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 +17 -12
- package/readme.md +207 -16
- package/ts/index.ts +6 -0
- package/ts/plugins.ts +22 -1
- package/ts/skr.api.ts +485 -0
- 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,401 @@
|
|
|
1
|
+
import * as plugins from './plugins.js';
|
|
2
|
+
/**
|
|
3
|
+
* Maps invoice data to SKR accounts
|
|
4
|
+
* Handles both SKR03 and SKR04 account mappings
|
|
5
|
+
*/
|
|
6
|
+
export class SKRInvoiceMapper {
|
|
7
|
+
constructor(skrType) {
|
|
8
|
+
// SKR03 account mappings
|
|
9
|
+
this.SKR03_ACCOUNTS = {
|
|
10
|
+
// Control accounts
|
|
11
|
+
vendorControl: '1600', // Verbindlichkeiten aus Lieferungen und Leistungen
|
|
12
|
+
customerControl: '1200', // Forderungen aus Lieferungen und Leistungen
|
|
13
|
+
// VAT accounts
|
|
14
|
+
inputVAT19: '1576', // Abziehbare Vorsteuer 19%
|
|
15
|
+
inputVAT7: '1571', // Abziehbare Vorsteuer 7%
|
|
16
|
+
outputVAT19: '1776', // Umsatzsteuer 19%
|
|
17
|
+
outputVAT7: '1771', // Umsatzsteuer 7%
|
|
18
|
+
reverseChargeVAT: '1577', // Abziehbare Vorsteuer §13b UStG
|
|
19
|
+
reverseChargePayable: '1787', // Umsatzsteuer §13b UStG
|
|
20
|
+
// Default expense/revenue accounts
|
|
21
|
+
defaultExpense: '4610', // Werbekosten
|
|
22
|
+
defaultRevenue: '8400', // Erlöse 19% USt
|
|
23
|
+
revenueReduced: '8300', // Erlöse 7% USt
|
|
24
|
+
revenueTaxFree: '8120', // Steuerfreie Umsätze
|
|
25
|
+
// Common expense accounts by category
|
|
26
|
+
materialExpense: '5000', // Aufwendungen für Roh-, Hilfs- und Betriebsstoffe
|
|
27
|
+
merchandiseExpense: '5400', // Aufwendungen für Waren
|
|
28
|
+
personnelExpense: '6000', // Löhne und Gehälter
|
|
29
|
+
rentExpense: '4200', // Miete
|
|
30
|
+
officeExpense: '4930', // Bürobedarf
|
|
31
|
+
travelExpense: '4670', // Reisekosten
|
|
32
|
+
vehicleExpense: '4530', // Kfz-Kosten
|
|
33
|
+
// Skonto accounts
|
|
34
|
+
skontoExpense: '4736', // Erhaltene Skonti 19% USt
|
|
35
|
+
skontoRevenue: '8736', // Gewährte Skonti 19% USt
|
|
36
|
+
// Intra-EU accounts
|
|
37
|
+
intraEUAcquisition: '8125', // Steuerfreie innergemeinschaftliche Erwerbe
|
|
38
|
+
intraEUSupply: '8125' // Steuerfreie innergemeinschaftliche Lieferungen
|
|
39
|
+
};
|
|
40
|
+
// SKR04 account mappings
|
|
41
|
+
this.SKR04_ACCOUNTS = {
|
|
42
|
+
// Control accounts
|
|
43
|
+
vendorControl: '3300', // Verbindlichkeiten aus Lieferungen und Leistungen
|
|
44
|
+
customerControl: '1400', // Forderungen aus Lieferungen und Leistungen
|
|
45
|
+
// VAT accounts
|
|
46
|
+
inputVAT19: '1406', // Abziehbare Vorsteuer 19%
|
|
47
|
+
inputVAT7: '1401', // Abziehbare Vorsteuer 7%
|
|
48
|
+
outputVAT19: '3806', // Umsatzsteuer 19%
|
|
49
|
+
outputVAT7: '3801', // Umsatzsteuer 7%
|
|
50
|
+
reverseChargeVAT: '1407', // Abziehbare Vorsteuer §13b UStG
|
|
51
|
+
reverseChargePayable: '3837', // Umsatzsteuer §13b UStG
|
|
52
|
+
// Default expense/revenue accounts
|
|
53
|
+
defaultExpense: '6300', // Sonstige betriebliche Aufwendungen
|
|
54
|
+
defaultRevenue: '4400', // Erlöse 19% USt
|
|
55
|
+
revenueReduced: '4300', // Erlöse 7% USt
|
|
56
|
+
revenueTaxFree: '4120', // Steuerfreie Umsätze
|
|
57
|
+
// Common expense accounts by category
|
|
58
|
+
materialExpense: '5000', // Aufwendungen für Roh-, Hilfs- und Betriebsstoffe
|
|
59
|
+
merchandiseExpense: '5400', // Aufwendungen für Waren
|
|
60
|
+
personnelExpense: '6000', // Löhne
|
|
61
|
+
rentExpense: '6310', // Miete
|
|
62
|
+
officeExpense: '6815', // Bürobedarf
|
|
63
|
+
travelExpense: '6670', // Reisekosten
|
|
64
|
+
vehicleExpense: '6530', // Kfz-Kosten
|
|
65
|
+
// Skonto accounts
|
|
66
|
+
skontoExpense: '4736', // Erhaltene Skonti 19% USt
|
|
67
|
+
skontoRevenue: '8736', // Gewährte Skonti 19% USt
|
|
68
|
+
// Intra-EU accounts
|
|
69
|
+
intraEUAcquisition: '4125', // Steuerfreie innergemeinschaftliche Erwerbe
|
|
70
|
+
intraEUSupply: '4125' // Steuerfreie innergemeinschaftliche Lieferungen
|
|
71
|
+
};
|
|
72
|
+
// Product category to account mappings
|
|
73
|
+
this.CATEGORY_MAPPINGS = {
|
|
74
|
+
'MATERIAL': { skr03: '5000', skr04: '5000' },
|
|
75
|
+
'MERCHANDISE': { skr03: '5400', skr04: '5400' },
|
|
76
|
+
'SERVICE': { skr03: '4610', skr04: '6300' },
|
|
77
|
+
'OFFICE': { skr03: '4930', skr04: '6815' },
|
|
78
|
+
'IT': { skr03: '4940', skr04: '6825' },
|
|
79
|
+
'TRAVEL': { skr03: '4670', skr04: '6670' },
|
|
80
|
+
'VEHICLE': { skr03: '4530', skr04: '6530' },
|
|
81
|
+
'RENT': { skr03: '4200', skr04: '6310' },
|
|
82
|
+
'UTILITIES': { skr03: '4240', skr04: '6320' },
|
|
83
|
+
'INSURANCE': { skr03: '4360', skr04: '6420' },
|
|
84
|
+
'MARKETING': { skr03: '4610', skr04: '6600' },
|
|
85
|
+
'CONSULTING': { skr03: '4640', skr04: '6650' },
|
|
86
|
+
'LEGAL': { skr03: '4790', skr04: '6790' },
|
|
87
|
+
'TELECOMMUNICATION': { skr03: '4920', skr04: '6805' }
|
|
88
|
+
};
|
|
89
|
+
this.skrType = skrType;
|
|
90
|
+
this.logger = new plugins.smartlog.ConsoleLog();
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Get account mappings for current SKR type
|
|
94
|
+
*/
|
|
95
|
+
getAccounts() {
|
|
96
|
+
return this.skrType === 'SKR03' ? this.SKR03_ACCOUNTS : this.SKR04_ACCOUNTS;
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Map invoice to booking rules
|
|
100
|
+
*/
|
|
101
|
+
mapInvoiceToSKR(invoice, customMappings) {
|
|
102
|
+
const accounts = this.getAccounts();
|
|
103
|
+
const taxScenario = invoice.taxScenario || 'domestic_taxed';
|
|
104
|
+
// Base booking rules
|
|
105
|
+
const bookingRules = {
|
|
106
|
+
skrType: this.skrType,
|
|
107
|
+
// Control accounts
|
|
108
|
+
vendorControlAccount: customMappings?.vendorControlAccount || accounts.vendorControl,
|
|
109
|
+
customerControlAccount: customMappings?.customerControlAccount || accounts.customerControl,
|
|
110
|
+
// VAT accounts
|
|
111
|
+
vatAccounts: {
|
|
112
|
+
inputVAT19: accounts.inputVAT19,
|
|
113
|
+
inputVAT7: accounts.inputVAT7,
|
|
114
|
+
outputVAT19: accounts.outputVAT19,
|
|
115
|
+
outputVAT7: accounts.outputVAT7,
|
|
116
|
+
reverseChargeVAT: accounts.reverseChargeVAT
|
|
117
|
+
},
|
|
118
|
+
// Default accounts
|
|
119
|
+
defaultExpenseAccount: accounts.defaultExpense,
|
|
120
|
+
defaultRevenueAccount: accounts.defaultRevenue,
|
|
121
|
+
// Skonto
|
|
122
|
+
skontoMethod: customMappings?.skontoMethod || 'gross',
|
|
123
|
+
skontoExpenseAccount: accounts.skontoExpense,
|
|
124
|
+
skontoRevenueAccount: accounts.skontoRevenue,
|
|
125
|
+
// Custom mappings
|
|
126
|
+
productCategoryMapping: customMappings?.productCategoryMapping || {},
|
|
127
|
+
vendorMapping: customMappings?.vendorMapping || {},
|
|
128
|
+
customerMapping: customMappings?.customerMapping || {}
|
|
129
|
+
};
|
|
130
|
+
return bookingRules;
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* Map invoice line to SKR account
|
|
134
|
+
*/
|
|
135
|
+
mapInvoiceLineToAccount(line, invoice, bookingRules) {
|
|
136
|
+
// Check if account is already specified
|
|
137
|
+
if (line.accountNumber) {
|
|
138
|
+
return line.accountNumber;
|
|
139
|
+
}
|
|
140
|
+
// For revenue (outbound invoices)
|
|
141
|
+
if (invoice.direction === 'outbound') {
|
|
142
|
+
return this.mapRevenueAccount(line, invoice, bookingRules);
|
|
143
|
+
}
|
|
144
|
+
// For expenses (inbound invoices)
|
|
145
|
+
return this.mapExpenseAccount(line, invoice, bookingRules);
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* Map revenue account based on VAT rate and scenario
|
|
149
|
+
*/
|
|
150
|
+
mapRevenueAccount(line, invoice, bookingRules) {
|
|
151
|
+
const accounts = this.getAccounts();
|
|
152
|
+
const vatRate = line.vatCategory.rate;
|
|
153
|
+
// Check tax scenario
|
|
154
|
+
switch (invoice.taxScenario) {
|
|
155
|
+
case 'intra_eu_supply':
|
|
156
|
+
return accounts.intraEUSupply;
|
|
157
|
+
case 'export':
|
|
158
|
+
case 'domestic_exempt':
|
|
159
|
+
return accounts.revenueTaxFree;
|
|
160
|
+
case 'domestic_taxed':
|
|
161
|
+
default:
|
|
162
|
+
// Map by VAT rate
|
|
163
|
+
if (vatRate === 19) {
|
|
164
|
+
return accounts.defaultRevenue;
|
|
165
|
+
}
|
|
166
|
+
else if (vatRate === 7) {
|
|
167
|
+
return accounts.revenueReduced;
|
|
168
|
+
}
|
|
169
|
+
else if (vatRate === 0) {
|
|
170
|
+
return accounts.revenueTaxFree;
|
|
171
|
+
}
|
|
172
|
+
return accounts.defaultRevenue;
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
/**
|
|
176
|
+
* Map expense account based on product category and vendor
|
|
177
|
+
*/
|
|
178
|
+
mapExpenseAccount(line, invoice, bookingRules) {
|
|
179
|
+
const accounts = this.getAccounts();
|
|
180
|
+
// Check vendor-specific mapping
|
|
181
|
+
const vendorId = invoice.supplier.id;
|
|
182
|
+
if (bookingRules.vendorMapping && bookingRules.vendorMapping[vendorId]) {
|
|
183
|
+
return bookingRules.vendorMapping[vendorId];
|
|
184
|
+
}
|
|
185
|
+
// Try to determine category from line description
|
|
186
|
+
const category = this.detectProductCategory(line.description);
|
|
187
|
+
if (category) {
|
|
188
|
+
const mapping = this.CATEGORY_MAPPINGS[category];
|
|
189
|
+
if (mapping) {
|
|
190
|
+
return this.skrType === 'SKR03' ? mapping.skr03 : mapping.skr04;
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
// Check product category mapping
|
|
194
|
+
if (line.productCode && bookingRules.productCategoryMapping) {
|
|
195
|
+
const mappedAccount = bookingRules.productCategoryMapping[line.productCode];
|
|
196
|
+
if (mappedAccount) {
|
|
197
|
+
return mappedAccount;
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
// Default expense account
|
|
201
|
+
return bookingRules.defaultExpenseAccount;
|
|
202
|
+
}
|
|
203
|
+
/**
|
|
204
|
+
* Detect product category from description
|
|
205
|
+
*/
|
|
206
|
+
detectProductCategory(description) {
|
|
207
|
+
const lowerDesc = description.toLowerCase();
|
|
208
|
+
const categoryKeywords = {
|
|
209
|
+
'MATERIAL': ['material', 'rohstoff', 'raw material', 'component'],
|
|
210
|
+
'MERCHANDISE': ['ware', 'merchandise', 'product', 'artikel'],
|
|
211
|
+
'SERVICE': ['service', 'dienstleistung', 'beratung', 'support'],
|
|
212
|
+
'OFFICE': ['büro', 'office', 'papier', 'stationery'],
|
|
213
|
+
'IT': ['software', 'hardware', 'computer', 'lizenz', 'license'],
|
|
214
|
+
'TRAVEL': ['reise', 'travel', 'hotel', 'flug', 'flight'],
|
|
215
|
+
'VEHICLE': ['kfz', 'vehicle', 'auto', 'benzin', 'fuel'],
|
|
216
|
+
'RENT': ['miete', 'rent', 'lease', 'pacht'],
|
|
217
|
+
'UTILITIES': ['strom', 'wasser', 'gas', 'energie', 'electricity', 'water'],
|
|
218
|
+
'INSURANCE': ['versicherung', 'insurance'],
|
|
219
|
+
'MARKETING': ['werbung', 'marketing', 'advertising', 'kampagne'],
|
|
220
|
+
'CONSULTING': ['beratung', 'consulting', 'advisory'],
|
|
221
|
+
'LEGAL': ['rechts', 'legal', 'anwalt', 'lawyer', 'notar'],
|
|
222
|
+
'TELECOMMUNICATION': ['telefon', 'internet', 'mobilfunk', 'telekom']
|
|
223
|
+
};
|
|
224
|
+
for (const [category, keywords] of Object.entries(categoryKeywords)) {
|
|
225
|
+
if (keywords.some(keyword => lowerDesc.includes(keyword))) {
|
|
226
|
+
return category;
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
return undefined;
|
|
230
|
+
}
|
|
231
|
+
/**
|
|
232
|
+
* Get VAT account for given VAT category and rate
|
|
233
|
+
*/
|
|
234
|
+
getVATAccount(vatCategory, direction, taxScenario) {
|
|
235
|
+
const accounts = this.getAccounts();
|
|
236
|
+
// Handle reverse charge
|
|
237
|
+
if (taxScenario === 'reverse_charge' || vatCategory.code === 'AE') {
|
|
238
|
+
return direction === 'input'
|
|
239
|
+
? accounts.reverseChargeVAT
|
|
240
|
+
: accounts.reverseChargePayable;
|
|
241
|
+
}
|
|
242
|
+
// Standard VAT accounts by rate
|
|
243
|
+
if (direction === 'input') {
|
|
244
|
+
if (vatCategory.rate === 19) {
|
|
245
|
+
return accounts.inputVAT19;
|
|
246
|
+
}
|
|
247
|
+
else if (vatCategory.rate === 7) {
|
|
248
|
+
return accounts.inputVAT7;
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
else {
|
|
252
|
+
if (vatCategory.rate === 19) {
|
|
253
|
+
return accounts.outputVAT19;
|
|
254
|
+
}
|
|
255
|
+
else if (vatCategory.rate === 7) {
|
|
256
|
+
return accounts.outputVAT7;
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
// Default to 19% if rate is not standard
|
|
260
|
+
return direction === 'input' ? accounts.inputVAT19 : accounts.outputVAT19;
|
|
261
|
+
}
|
|
262
|
+
/**
|
|
263
|
+
* Get control account for party
|
|
264
|
+
*/
|
|
265
|
+
getControlAccount(invoice, bookingRules) {
|
|
266
|
+
if (invoice.direction === 'inbound') {
|
|
267
|
+
// Check vendor-specific control account
|
|
268
|
+
const vendorId = invoice.supplier.id;
|
|
269
|
+
if (bookingRules.vendorMapping && bookingRules.vendorMapping[vendorId]) {
|
|
270
|
+
const customAccount = bookingRules.vendorMapping[vendorId];
|
|
271
|
+
// Check if it's a control account (starts with 16 for SKR03 or 33 for SKR04)
|
|
272
|
+
if (this.isControlAccount(customAccount)) {
|
|
273
|
+
return customAccount;
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
return bookingRules.vendorControlAccount;
|
|
277
|
+
}
|
|
278
|
+
else {
|
|
279
|
+
// Check customer-specific control account
|
|
280
|
+
const customerId = invoice.customer.id;
|
|
281
|
+
if (bookingRules.customerMapping && bookingRules.customerMapping[customerId]) {
|
|
282
|
+
const customAccount = bookingRules.customerMapping[customerId];
|
|
283
|
+
// Check if it's a control account (starts with 12 for SKR03 or 14 for SKR04)
|
|
284
|
+
if (this.isControlAccount(customAccount)) {
|
|
285
|
+
return customAccount;
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
return bookingRules.customerControlAccount;
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
/**
|
|
292
|
+
* Check if account is a control account
|
|
293
|
+
*/
|
|
294
|
+
isControlAccount(accountNumber) {
|
|
295
|
+
if (this.skrType === 'SKR03') {
|
|
296
|
+
return accountNumber.startsWith('12') || accountNumber.startsWith('16');
|
|
297
|
+
}
|
|
298
|
+
else {
|
|
299
|
+
return accountNumber.startsWith('14') || accountNumber.startsWith('33');
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
/**
|
|
303
|
+
* Get skonto accounts
|
|
304
|
+
*/
|
|
305
|
+
getSkontoAccounts(invoice) {
|
|
306
|
+
const accounts = this.getAccounts();
|
|
307
|
+
if (invoice.direction === 'inbound') {
|
|
308
|
+
// Received skonto (expense reduction)
|
|
309
|
+
return {
|
|
310
|
+
skontoAccount: accounts.skontoExpense,
|
|
311
|
+
vatCorrectionAccount: accounts.inputVAT19 // VAT correction
|
|
312
|
+
};
|
|
313
|
+
}
|
|
314
|
+
else {
|
|
315
|
+
// Granted skonto (revenue reduction)
|
|
316
|
+
return {
|
|
317
|
+
skontoAccount: accounts.skontoRevenue,
|
|
318
|
+
vatCorrectionAccount: accounts.outputVAT19 // VAT correction
|
|
319
|
+
};
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
/**
|
|
323
|
+
* Validate account number format
|
|
324
|
+
*/
|
|
325
|
+
validateAccountNumber(accountNumber) {
|
|
326
|
+
// SKR accounts are typically 4 digits, sometimes with sub-accounts
|
|
327
|
+
const accountPattern = /^\d{4}(\d{0,2})?$/;
|
|
328
|
+
return accountPattern.test(accountNumber);
|
|
329
|
+
}
|
|
330
|
+
/**
|
|
331
|
+
* Get account description
|
|
332
|
+
*/
|
|
333
|
+
getAccountDescription(accountNumber) {
|
|
334
|
+
// This would typically look up from a complete SKR account database
|
|
335
|
+
// For now, return a basic description
|
|
336
|
+
const commonAccounts = {
|
|
337
|
+
// SKR03
|
|
338
|
+
'1200': 'Forderungen aus Lieferungen und Leistungen',
|
|
339
|
+
'1600': 'Verbindlichkeiten aus Lieferungen und Leistungen',
|
|
340
|
+
'1576': 'Abziehbare Vorsteuer 19%',
|
|
341
|
+
'1571': 'Abziehbare Vorsteuer 7%',
|
|
342
|
+
'1776': 'Umsatzsteuer 19%',
|
|
343
|
+
'1771': 'Umsatzsteuer 7%',
|
|
344
|
+
'4610': 'Werbekosten',
|
|
345
|
+
'8400': 'Erlöse 19% USt',
|
|
346
|
+
'8300': 'Erlöse 7% USt',
|
|
347
|
+
// SKR04
|
|
348
|
+
'1400': 'Forderungen aus Lieferungen und Leistungen',
|
|
349
|
+
'3300': 'Verbindlichkeiten aus Lieferungen und Leistungen',
|
|
350
|
+
'1406': 'Abziehbare Vorsteuer 19%',
|
|
351
|
+
'1401': 'Abziehbare Vorsteuer 7%',
|
|
352
|
+
'3806': 'Umsatzsteuer 19%',
|
|
353
|
+
'3801': 'Umsatzsteuer 7%',
|
|
354
|
+
'6300': 'Sonstige betriebliche Aufwendungen',
|
|
355
|
+
'4400': 'Erlöse 19% USt',
|
|
356
|
+
'4300': 'Erlöse 7% USt'
|
|
357
|
+
};
|
|
358
|
+
return commonAccounts[accountNumber] || `Account ${accountNumber}`;
|
|
359
|
+
}
|
|
360
|
+
/**
|
|
361
|
+
* Calculate booking confidence score
|
|
362
|
+
*/
|
|
363
|
+
calculateConfidence(invoice, bookingRules) {
|
|
364
|
+
let confidence = 100;
|
|
365
|
+
// Reduce confidence for missing or uncertain mappings
|
|
366
|
+
invoice.lines.forEach(line => {
|
|
367
|
+
if (!line.accountNumber) {
|
|
368
|
+
confidence -= 10; // No explicit account mapping
|
|
369
|
+
}
|
|
370
|
+
if (!line.productCode) {
|
|
371
|
+
confidence -= 5; // No product code for mapping
|
|
372
|
+
}
|
|
373
|
+
});
|
|
374
|
+
// Reduce confidence for complex tax scenarios
|
|
375
|
+
if (invoice.taxScenario === 'reverse_charge' ||
|
|
376
|
+
invoice.taxScenario === 'intra_eu_acquisition') {
|
|
377
|
+
confidence -= 15;
|
|
378
|
+
}
|
|
379
|
+
// Reduce confidence for mixed VAT rates
|
|
380
|
+
if (invoice.vatBreakdown.length > 1) {
|
|
381
|
+
confidence -= 10;
|
|
382
|
+
}
|
|
383
|
+
// Reduce confidence if no vendor/customer mapping exists
|
|
384
|
+
if (invoice.direction === 'inbound') {
|
|
385
|
+
if (!bookingRules.vendorMapping?.[invoice.supplier.id]) {
|
|
386
|
+
confidence -= 10;
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
else {
|
|
390
|
+
if (!bookingRules.customerMapping?.[invoice.customer.id]) {
|
|
391
|
+
confidence -= 10;
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
// Reduce confidence for credit notes
|
|
395
|
+
if (invoice.invoiceTypeCode === '381') {
|
|
396
|
+
confidence -= 10;
|
|
397
|
+
}
|
|
398
|
+
return Math.max(0, confidence);
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2tyLmludm9pY2UubWFwcGVyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vdHMvc2tyLmludm9pY2UubWFwcGVyLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sS0FBSyxPQUFPLE1BQU0sY0FBYyxDQUFDO0FBVXhDOzs7R0FHRztBQUNILE1BQU0sT0FBTyxnQkFBZ0I7SUFrRzNCLFlBQVksT0FBaUI7UUE5RjdCLHlCQUF5QjtRQUNSLG1CQUFjLEdBQUc7WUFDaEMsbUJBQW1CO1lBQ25CLGFBQWEsRUFBRSxNQUFNLEVBQVksbURBQW1EO1lBQ3BGLGVBQWUsRUFBRSxNQUFNLEVBQVUsNkNBQTZDO1lBRTlFLGVBQWU7WUFDZixVQUFVLEVBQUUsTUFBTSxFQUFlLDJCQUEyQjtZQUM1RCxTQUFTLEVBQUUsTUFBTSxFQUFnQiwwQkFBMEI7WUFDM0QsV0FBVyxFQUFFLE1BQU0sRUFBYyxtQkFBbUI7WUFDcEQsVUFBVSxFQUFFLE1BQU0sRUFBZSxrQkFBa0I7WUFDbkQsZ0JBQWdCLEVBQUUsTUFBTSxFQUFTLGlDQUFpQztZQUNsRSxvQkFBb0IsRUFBRSxNQUFNLEVBQUkseUJBQXlCO1lBRXpELG1DQUFtQztZQUNuQyxjQUFjLEVBQUUsTUFBTSxFQUFXLGNBQWM7WUFDL0MsY0FBYyxFQUFFLE1BQU0sRUFBVyxpQkFBaUI7WUFDbEQsY0FBYyxFQUFFLE1BQU0sRUFBVyxnQkFBZ0I7WUFDakQsY0FBYyxFQUFFLE1BQU0sRUFBVyxzQkFBc0I7WUFFdkQsc0NBQXNDO1lBQ3RDLGVBQWUsRUFBRSxNQUFNLEVBQVUsbURBQW1EO1lBQ3BGLGtCQUFrQixFQUFFLE1BQU0sRUFBTyx5QkFBeUI7WUFDMUQsZ0JBQWdCLEVBQUUsTUFBTSxFQUFTLHFCQUFxQjtZQUN0RCxXQUFXLEVBQUUsTUFBTSxFQUFjLFFBQVE7WUFDekMsYUFBYSxFQUFFLE1BQU0sRUFBWSxhQUFhO1lBQzlDLGFBQWEsRUFBRSxNQUFNLEVBQVksY0FBYztZQUMvQyxjQUFjLEVB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
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
import type { IInvoice, IInvoiceFilter, IDuplicateCheckResult } from './skr.invoice.entity.js';
|
|
2
|
+
/**
|
|
3
|
+
* Invoice storage metadata
|
|
4
|
+
*/
|
|
5
|
+
export interface IInvoiceMetadata {
|
|
6
|
+
invoiceId: string;
|
|
7
|
+
invoiceNumber: string;
|
|
8
|
+
direction: 'inbound' | 'outbound';
|
|
9
|
+
issueDate: string;
|
|
10
|
+
supplierName: string;
|
|
11
|
+
customerName: string;
|
|
12
|
+
totalAmount: number;
|
|
13
|
+
currency: string;
|
|
14
|
+
contentHash: string;
|
|
15
|
+
pdfHash?: string;
|
|
16
|
+
xmlHash: string;
|
|
17
|
+
journalEntryId?: string;
|
|
18
|
+
transactionIds?: string[];
|
|
19
|
+
validationResult: {
|
|
20
|
+
isValid: boolean;
|
|
21
|
+
errors: number;
|
|
22
|
+
warnings: number;
|
|
23
|
+
};
|
|
24
|
+
parserVersion: string;
|
|
25
|
+
storedAt: string;
|
|
26
|
+
storedBy: string;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Invoice registry entry (for NDJSON streaming)
|
|
30
|
+
*/
|
|
31
|
+
export interface IInvoiceRegistryEntry {
|
|
32
|
+
id: string;
|
|
33
|
+
hash: string;
|
|
34
|
+
metadata: IInvoiceMetadata;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Storage statistics
|
|
38
|
+
*/
|
|
39
|
+
export interface IStorageStats {
|
|
40
|
+
totalInvoices: number;
|
|
41
|
+
inboundCount: number;
|
|
42
|
+
outboundCount: number;
|
|
43
|
+
totalSize: number;
|
|
44
|
+
duplicatesDetected: number;
|
|
45
|
+
lastUpdate: Date;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Content-addressed storage for invoices
|
|
49
|
+
* Integrates with BagIt archive structure for GoBD compliance
|
|
50
|
+
*/
|
|
51
|
+
export declare class InvoiceStorage {
|
|
52
|
+
private exportPath;
|
|
53
|
+
private logger;
|
|
54
|
+
private registryPath;
|
|
55
|
+
private metadataCache;
|
|
56
|
+
private readonly MAX_CACHE_SIZE;
|
|
57
|
+
private cacheAccessOrder;
|
|
58
|
+
constructor(exportPath: string);
|
|
59
|
+
/**
|
|
60
|
+
* Manage cache size using LRU eviction
|
|
61
|
+
*/
|
|
62
|
+
private manageCacheSize;
|
|
63
|
+
/**
|
|
64
|
+
* Update cache access order for LRU
|
|
65
|
+
*/
|
|
66
|
+
private touchCacheEntry;
|
|
67
|
+
/**
|
|
68
|
+
* Initialize storage directories
|
|
69
|
+
*/
|
|
70
|
+
initialize(): Promise<void>;
|
|
71
|
+
private readonly MAX_PDF_SIZE;
|
|
72
|
+
/**
|
|
73
|
+
* Store an invoice with content addressing
|
|
74
|
+
*/
|
|
75
|
+
storeInvoice(invoice: IInvoice, pdfBuffer?: Buffer): Promise<string>;
|
|
76
|
+
/**
|
|
77
|
+
* Retrieve an invoice by content hash
|
|
78
|
+
*/
|
|
79
|
+
retrieveInvoice(contentHash: string): Promise<IInvoice | null>;
|
|
80
|
+
/**
|
|
81
|
+
* Check for duplicate invoices
|
|
82
|
+
*/
|
|
83
|
+
checkDuplicate(invoice: IInvoice, contentHash: string): Promise<IDuplicateCheckResult>;
|
|
84
|
+
/**
|
|
85
|
+
* Search invoices by filter
|
|
86
|
+
*/
|
|
87
|
+
searchInvoices(filter: IInvoiceFilter): Promise<IInvoiceMetadata[]>;
|
|
88
|
+
/**
|
|
89
|
+
* Get storage statistics
|
|
90
|
+
*/
|
|
91
|
+
getStatistics(): Promise<IStorageStats>;
|
|
92
|
+
/**
|
|
93
|
+
* Create EN16931 compliance report
|
|
94
|
+
*/
|
|
95
|
+
createComplianceReport(): Promise<void>;
|
|
96
|
+
/**
|
|
97
|
+
* Load registry from disk
|
|
98
|
+
*/
|
|
99
|
+
private loadRegistry;
|
|
100
|
+
/**
|
|
101
|
+
* Update registry with new entry
|
|
102
|
+
*/
|
|
103
|
+
private updateRegistry;
|
|
104
|
+
/**
|
|
105
|
+
* Find invoice file by hash and extension
|
|
106
|
+
*/
|
|
107
|
+
private findInvoiceFile;
|
|
108
|
+
/**
|
|
109
|
+
* Calculate SHA-256 hash
|
|
110
|
+
*/
|
|
111
|
+
private calculateHash;
|
|
112
|
+
/**
|
|
113
|
+
* Check if metadata matches filter
|
|
114
|
+
*/
|
|
115
|
+
private matchesFilter;
|
|
116
|
+
/**
|
|
117
|
+
* Count errors in validation result
|
|
118
|
+
*/
|
|
119
|
+
private countErrors;
|
|
120
|
+
/**
|
|
121
|
+
* Count warnings in validation result
|
|
122
|
+
*/
|
|
123
|
+
private countWarnings;
|
|
124
|
+
/**
|
|
125
|
+
* Clean up old invoices (for testing only)
|
|
126
|
+
*/
|
|
127
|
+
cleanup(olderThanDays?: number): Promise<number>;
|
|
128
|
+
/**
|
|
129
|
+
* Set cache entry with LRU eviction
|
|
130
|
+
*/
|
|
131
|
+
private setCacheEntry;
|
|
132
|
+
/**
|
|
133
|
+
* Get cache entry and update access order
|
|
134
|
+
*/
|
|
135
|
+
private getCacheEntry;
|
|
136
|
+
/**
|
|
137
|
+
* Update metadata in storage and cache
|
|
138
|
+
*/
|
|
139
|
+
updateMetadata(contentHash: string, updates: Partial<IInvoiceMetadata>): Promise<void>;
|
|
140
|
+
}
|