@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,98 @@
|
|
|
1
|
+
import type { IInvoice, TInvoiceFormat, TInvoiceDirection } from './skr.invoice.entity.js';
|
|
2
|
+
/**
|
|
3
|
+
* Adapter for @fin.cx/einvoice library
|
|
4
|
+
* Handles parsing, validation, and format conversion of e-invoices
|
|
5
|
+
*/
|
|
6
|
+
export declare class InvoiceAdapter {
|
|
7
|
+
private logger;
|
|
8
|
+
constructor();
|
|
9
|
+
private readonly MAX_XML_SIZE;
|
|
10
|
+
private readonly MAX_PDF_SIZE;
|
|
11
|
+
/**
|
|
12
|
+
* Parse an invoice from file or buffer
|
|
13
|
+
*/
|
|
14
|
+
parseInvoice(file: Buffer | string, direction: TInvoiceDirection): Promise<IInvoice>;
|
|
15
|
+
/**
|
|
16
|
+
* Validate an invoice using multi-level validation
|
|
17
|
+
*/
|
|
18
|
+
private validateInvoice;
|
|
19
|
+
/**
|
|
20
|
+
* Map EN16931 Business Terms to internal invoice model
|
|
21
|
+
*/
|
|
22
|
+
private mapToInternalModel;
|
|
23
|
+
/**
|
|
24
|
+
* Map party information
|
|
25
|
+
*/
|
|
26
|
+
private mapParty;
|
|
27
|
+
/**
|
|
28
|
+
* Map bank account information
|
|
29
|
+
*/
|
|
30
|
+
private mapBankAccount;
|
|
31
|
+
/**
|
|
32
|
+
* Map invoice lines
|
|
33
|
+
*/
|
|
34
|
+
private mapInvoiceLines;
|
|
35
|
+
/**
|
|
36
|
+
* Map VAT category
|
|
37
|
+
*/
|
|
38
|
+
private mapVATCategory;
|
|
39
|
+
/**
|
|
40
|
+
* Get exemption reason for VAT category
|
|
41
|
+
*/
|
|
42
|
+
private getExemptionReason;
|
|
43
|
+
/**
|
|
44
|
+
* Map VAT breakdown
|
|
45
|
+
*/
|
|
46
|
+
private mapVATBreakdown;
|
|
47
|
+
/**
|
|
48
|
+
* Map allowances and charges
|
|
49
|
+
*/
|
|
50
|
+
private mapAllowancesCharges;
|
|
51
|
+
/**
|
|
52
|
+
* Map line-level allowances and charges
|
|
53
|
+
*/
|
|
54
|
+
private mapLineAllowancesCharges;
|
|
55
|
+
/**
|
|
56
|
+
* Map payment terms
|
|
57
|
+
*/
|
|
58
|
+
private mapPaymentTerms;
|
|
59
|
+
/**
|
|
60
|
+
* Parse skonto terms from payment terms text
|
|
61
|
+
*/
|
|
62
|
+
private parseSkontoTerms;
|
|
63
|
+
/**
|
|
64
|
+
* Map payment means
|
|
65
|
+
*/
|
|
66
|
+
private mapPaymentMeans;
|
|
67
|
+
/**
|
|
68
|
+
* Classify tax scenario based on invoice data
|
|
69
|
+
*/
|
|
70
|
+
private classifyTaxScenario;
|
|
71
|
+
/**
|
|
72
|
+
* Check if country is in EU
|
|
73
|
+
*/
|
|
74
|
+
private isEUCountry;
|
|
75
|
+
/**
|
|
76
|
+
* Map e-invoice format from library format
|
|
77
|
+
*/
|
|
78
|
+
private mapEInvoiceFormat;
|
|
79
|
+
/**
|
|
80
|
+
* Calculate content hash for the invoice
|
|
81
|
+
*/
|
|
82
|
+
private calculateContentHash;
|
|
83
|
+
/**
|
|
84
|
+
* Convert invoice to different format
|
|
85
|
+
*/
|
|
86
|
+
convertFormat(invoice: IInvoice, targetFormat: TInvoiceFormat): Promise<string>;
|
|
87
|
+
/**
|
|
88
|
+
* Generate invoice from internal data
|
|
89
|
+
*/
|
|
90
|
+
generateInvoice(invoiceData: Partial<IInvoice>, format: TInvoiceFormat): Promise<{
|
|
91
|
+
xml: string;
|
|
92
|
+
pdf?: Buffer;
|
|
93
|
+
}>;
|
|
94
|
+
/**
|
|
95
|
+
* Map internal invoice to EN16931 Business Terms
|
|
96
|
+
*/
|
|
97
|
+
private mapToBusinessTerms;
|
|
98
|
+
}
|
|
@@ -0,0 +1,476 @@
|
|
|
1
|
+
import * as plugins from './plugins.js';
|
|
2
|
+
/**
|
|
3
|
+
* Adapter for @fin.cx/einvoice library
|
|
4
|
+
* Handles parsing, validation, and format conversion of e-invoices
|
|
5
|
+
*/
|
|
6
|
+
export class InvoiceAdapter {
|
|
7
|
+
constructor() {
|
|
8
|
+
this.MAX_XML_SIZE = 10 * 1024 * 1024; // 10MB max
|
|
9
|
+
this.MAX_PDF_SIZE = 50 * 1024 * 1024; // 50MB max
|
|
10
|
+
this.logger = new plugins.smartlog.ConsoleLog();
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Parse an invoice from file or buffer
|
|
14
|
+
*/
|
|
15
|
+
async parseInvoice(file, direction) {
|
|
16
|
+
try {
|
|
17
|
+
// Validate input size
|
|
18
|
+
if (Buffer.isBuffer(file)) {
|
|
19
|
+
if (file.length > this.MAX_XML_SIZE) {
|
|
20
|
+
throw new Error(`Invoice file too large: ${file.length} bytes (max ${this.MAX_XML_SIZE} bytes)`);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
else if (typeof file === 'string' && file.length > this.MAX_XML_SIZE) {
|
|
24
|
+
throw new Error(`Invoice XML too large: ${file.length} characters (max ${this.MAX_XML_SIZE} characters)`);
|
|
25
|
+
}
|
|
26
|
+
// Parse the invoice using @fin.cx/einvoice
|
|
27
|
+
let einvoice;
|
|
28
|
+
if (typeof file === 'string') {
|
|
29
|
+
einvoice = await plugins.einvoice.EInvoice.fromXml(file);
|
|
30
|
+
}
|
|
31
|
+
else {
|
|
32
|
+
// Convert buffer to string first
|
|
33
|
+
const xmlString = file.toString('utf-8');
|
|
34
|
+
einvoice = await plugins.einvoice.EInvoice.fromXml(xmlString);
|
|
35
|
+
}
|
|
36
|
+
// Get detected format
|
|
37
|
+
const format = this.mapEInvoiceFormat(einvoice.format || 'xrechnung');
|
|
38
|
+
// Validate the invoice (takes ~2.2ms)
|
|
39
|
+
const validationResult = await this.validateInvoice(einvoice);
|
|
40
|
+
// Extract invoice data
|
|
41
|
+
const invoiceData = einvoice.toObject();
|
|
42
|
+
// Map to internal invoice model
|
|
43
|
+
const invoice = await this.mapToInternalModel(invoiceData, format, direction, validationResult);
|
|
44
|
+
// Store original XML content
|
|
45
|
+
invoice.xmlContent = einvoice.getXml();
|
|
46
|
+
// Calculate content hash
|
|
47
|
+
invoice.contentHash = await this.calculateContentHash(invoice.xmlContent);
|
|
48
|
+
// Classify tax scenario
|
|
49
|
+
invoice.taxScenario = this.classifyTaxScenario(invoice);
|
|
50
|
+
return invoice;
|
|
51
|
+
}
|
|
52
|
+
catch (error) {
|
|
53
|
+
this.logger.log('error', `Failed to parse invoice: ${error}`);
|
|
54
|
+
throw new Error(`Invoice parsing failed: ${error.message}`);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Validate an invoice using multi-level validation
|
|
59
|
+
*/
|
|
60
|
+
async validateInvoice(einvoice) {
|
|
61
|
+
// Perform multi-level validation
|
|
62
|
+
const validationResult = await einvoice.validate();
|
|
63
|
+
// Parse validation results into our structure
|
|
64
|
+
const syntaxResult = {
|
|
65
|
+
isValid: validationResult.syntax?.valid !== false,
|
|
66
|
+
errors: validationResult.syntax?.errors || [],
|
|
67
|
+
warnings: validationResult.syntax?.warnings || []
|
|
68
|
+
};
|
|
69
|
+
const semanticResult = {
|
|
70
|
+
isValid: validationResult.semantic?.valid !== false,
|
|
71
|
+
errors: validationResult.semantic?.errors || [],
|
|
72
|
+
warnings: validationResult.semantic?.warnings || []
|
|
73
|
+
};
|
|
74
|
+
const businessResult = {
|
|
75
|
+
isValid: validationResult.business?.valid !== false,
|
|
76
|
+
errors: validationResult.business?.errors || [],
|
|
77
|
+
warnings: validationResult.business?.warnings || []
|
|
78
|
+
};
|
|
79
|
+
const countryResult = {
|
|
80
|
+
isValid: validationResult.country?.valid !== false,
|
|
81
|
+
errors: validationResult.country?.errors || [],
|
|
82
|
+
warnings: validationResult.country?.warnings || []
|
|
83
|
+
};
|
|
84
|
+
return {
|
|
85
|
+
isValid: syntaxResult.isValid && semanticResult.isValid && businessResult.isValid,
|
|
86
|
+
syntax: {
|
|
87
|
+
valid: syntaxResult.isValid,
|
|
88
|
+
errors: syntaxResult.errors || [],
|
|
89
|
+
warnings: syntaxResult.warnings || []
|
|
90
|
+
},
|
|
91
|
+
semantic: {
|
|
92
|
+
valid: semanticResult.isValid,
|
|
93
|
+
errors: semanticResult.errors || [],
|
|
94
|
+
warnings: semanticResult.warnings || []
|
|
95
|
+
},
|
|
96
|
+
businessRules: {
|
|
97
|
+
valid: businessResult.isValid,
|
|
98
|
+
errors: businessResult.errors || [],
|
|
99
|
+
warnings: businessResult.warnings || []
|
|
100
|
+
},
|
|
101
|
+
countrySpecific: {
|
|
102
|
+
valid: countryResult.isValid,
|
|
103
|
+
errors: countryResult.errors || [],
|
|
104
|
+
warnings: countryResult.warnings || []
|
|
105
|
+
},
|
|
106
|
+
validatedAt: new Date(),
|
|
107
|
+
validatorVersion: '5.1.4'
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Map EN16931 Business Terms to internal invoice model
|
|
112
|
+
*/
|
|
113
|
+
async mapToInternalModel(businessTerms, format, direction, validationResult) {
|
|
114
|
+
const invoice = {
|
|
115
|
+
// Identity
|
|
116
|
+
id: plugins.smartunique.shortId(),
|
|
117
|
+
direction,
|
|
118
|
+
format,
|
|
119
|
+
// EN16931 Business Terms
|
|
120
|
+
invoiceNumber: businessTerms.BT1_InvoiceNumber,
|
|
121
|
+
issueDate: new Date(businessTerms.BT2_IssueDate),
|
|
122
|
+
invoiceTypeCode: businessTerms.BT3_InvoiceTypeCode || '380',
|
|
123
|
+
currencyCode: businessTerms.BT5_CurrencyCode || 'EUR',
|
|
124
|
+
taxCurrencyCode: businessTerms.BT6_TaxCurrencyCode,
|
|
125
|
+
taxPointDate: businessTerms.BT7_TaxPointDate ? new Date(businessTerms.BT7_TaxPointDate) : undefined,
|
|
126
|
+
paymentDueDate: businessTerms.BT9_PaymentDueDate ? new Date(businessTerms.BT9_PaymentDueDate) : undefined,
|
|
127
|
+
buyerReference: businessTerms.BT10_BuyerReference,
|
|
128
|
+
projectReference: businessTerms.BT11_ProjectReference,
|
|
129
|
+
contractReference: businessTerms.BT12_ContractReference,
|
|
130
|
+
orderReference: businessTerms.BT13_OrderReference,
|
|
131
|
+
sellerOrderReference: businessTerms.BT14_SellerOrderReference,
|
|
132
|
+
// Parties
|
|
133
|
+
supplier: this.mapParty(businessTerms.BG4_Seller),
|
|
134
|
+
customer: this.mapParty(businessTerms.BG7_Buyer),
|
|
135
|
+
payee: businessTerms.BG10_Payee ? this.mapParty(businessTerms.BG10_Payee) : undefined,
|
|
136
|
+
// Line items
|
|
137
|
+
lines: this.mapInvoiceLines(businessTerms.BG25_InvoiceLines || []),
|
|
138
|
+
// Allowances and charges
|
|
139
|
+
allowances: this.mapAllowancesCharges(businessTerms.BG20_DocumentAllowances || [], true),
|
|
140
|
+
charges: this.mapAllowancesCharges(businessTerms.BG21_DocumentCharges || [], false),
|
|
141
|
+
// Amounts
|
|
142
|
+
lineNetAmount: parseFloat(businessTerms.BT106_SumOfLineNetAmounts || 0),
|
|
143
|
+
allowanceTotalAmount: parseFloat(businessTerms.BT107_AllowanceTotalAmount || 0),
|
|
144
|
+
chargeTotalAmount: parseFloat(businessTerms.BT108_ChargeTotalAmount || 0),
|
|
145
|
+
taxExclusiveAmount: parseFloat(businessTerms.BT109_TaxExclusiveAmount || 0),
|
|
146
|
+
taxInclusiveAmount: parseFloat(businessTerms.BT112_TaxInclusiveAmount || 0),
|
|
147
|
+
prepaidAmount: parseFloat(businessTerms.BT113_PrepaidAmount || 0),
|
|
148
|
+
payableAmount: parseFloat(businessTerms.BT115_PayableAmount || 0),
|
|
149
|
+
// VAT breakdown
|
|
150
|
+
vatBreakdown: this.mapVATBreakdown(businessTerms.BG23_VATBreakdown || []),
|
|
151
|
+
totalVATAmount: parseFloat(businessTerms.BT110_TotalVATAmount || 0),
|
|
152
|
+
// Payment
|
|
153
|
+
paymentTerms: this.mapPaymentTerms(businessTerms),
|
|
154
|
+
paymentMeans: this.mapPaymentMeans(businessTerms.BG16_PaymentInstructions),
|
|
155
|
+
// Notes
|
|
156
|
+
invoiceNote: businessTerms.BT22_InvoiceNote,
|
|
157
|
+
// Processing metadata
|
|
158
|
+
status: 'validated',
|
|
159
|
+
// Storage (to be filled later)
|
|
160
|
+
contentHash: '',
|
|
161
|
+
// Validation
|
|
162
|
+
validationResult,
|
|
163
|
+
// Audit trail
|
|
164
|
+
createdAt: new Date(),
|
|
165
|
+
createdBy: 'system',
|
|
166
|
+
// Metadata
|
|
167
|
+
metadata: {
|
|
168
|
+
importedAt: new Date(),
|
|
169
|
+
parserVersion: '5.1.4',
|
|
170
|
+
originalFormat: format
|
|
171
|
+
}
|
|
172
|
+
};
|
|
173
|
+
return invoice;
|
|
174
|
+
}
|
|
175
|
+
/**
|
|
176
|
+
* Map party information
|
|
177
|
+
*/
|
|
178
|
+
mapParty(partyData) {
|
|
179
|
+
if (!partyData) {
|
|
180
|
+
return {
|
|
181
|
+
id: '',
|
|
182
|
+
name: '',
|
|
183
|
+
address: { countryCode: 'DE' }
|
|
184
|
+
};
|
|
185
|
+
}
|
|
186
|
+
return {
|
|
187
|
+
id: partyData.BT29_SellerID || partyData.BT46_BuyerID || plugins.smartunique.shortId(),
|
|
188
|
+
name: partyData.BT27_SellerName || partyData.BT44_BuyerName || '',
|
|
189
|
+
address: {
|
|
190
|
+
street: partyData.BT35_SellerStreet || partyData.BT50_BuyerStreet,
|
|
191
|
+
city: partyData.BT37_SellerCity || partyData.BT52_BuyerCity,
|
|
192
|
+
postalCode: partyData.BT38_SellerPostalCode || partyData.BT53_BuyerPostalCode,
|
|
193
|
+
countryCode: partyData.BT40_SellerCountryCode || partyData.BT55_BuyerCountryCode || 'DE'
|
|
194
|
+
},
|
|
195
|
+
vatId: partyData.BT31_SellerVATID || partyData.BT48_BuyerVATID,
|
|
196
|
+
taxId: partyData.BT32_SellerTaxID || partyData.BT47_BuyerTaxID,
|
|
197
|
+
email: partyData.BT34_SellerEmail || partyData.BT49_BuyerEmail,
|
|
198
|
+
phone: partyData.BT33_SellerPhone,
|
|
199
|
+
bankAccount: this.mapBankAccount(partyData)
|
|
200
|
+
};
|
|
201
|
+
}
|
|
202
|
+
/**
|
|
203
|
+
* Map bank account information
|
|
204
|
+
*/
|
|
205
|
+
mapBankAccount(partyData) {
|
|
206
|
+
if (!partyData?.BT84_PaymentAccountID) {
|
|
207
|
+
return undefined;
|
|
208
|
+
}
|
|
209
|
+
return {
|
|
210
|
+
iban: partyData.BT84_PaymentAccountID,
|
|
211
|
+
bic: partyData.BT86_PaymentServiceProviderID,
|
|
212
|
+
accountHolder: partyData.BT85_PaymentAccountName
|
|
213
|
+
};
|
|
214
|
+
}
|
|
215
|
+
/**
|
|
216
|
+
* Map invoice lines
|
|
217
|
+
*/
|
|
218
|
+
mapInvoiceLines(linesData) {
|
|
219
|
+
return linesData.map((line, index) => ({
|
|
220
|
+
lineNumber: index + 1,
|
|
221
|
+
description: line.BT154_ItemDescription || '',
|
|
222
|
+
quantity: parseFloat(line.BT129_Quantity || 1),
|
|
223
|
+
unitPrice: parseFloat(line.BT146_NetPrice || 0),
|
|
224
|
+
netAmount: parseFloat(line.BT131_LineNetAmount || 0),
|
|
225
|
+
vatCategory: this.mapVATCategory(line.BT151_ItemVATCategory, line.BT152_ItemVATRate),
|
|
226
|
+
vatAmount: parseFloat(line.lineVATAmount || 0),
|
|
227
|
+
grossAmount: parseFloat(line.BT131_LineNetAmount || 0) + parseFloat(line.lineVATAmount || 0),
|
|
228
|
+
productCode: line.BT155_ItemSellerID,
|
|
229
|
+
allowances: this.mapLineAllowancesCharges(line.BG27_LineAllowances || [], true),
|
|
230
|
+
charges: this.mapLineAllowancesCharges(line.BG28_LineCharges || [], false)
|
|
231
|
+
}));
|
|
232
|
+
}
|
|
233
|
+
/**
|
|
234
|
+
* Map VAT category
|
|
235
|
+
*/
|
|
236
|
+
mapVATCategory(categoryCode, rate) {
|
|
237
|
+
const vatRate = typeof rate === 'string' ? parseFloat(rate) : rate;
|
|
238
|
+
return {
|
|
239
|
+
code: categoryCode || 'S',
|
|
240
|
+
rate: vatRate || 0,
|
|
241
|
+
exemptionReason: this.getExemptionReason(categoryCode)
|
|
242
|
+
};
|
|
243
|
+
}
|
|
244
|
+
/**
|
|
245
|
+
* Get exemption reason for VAT category
|
|
246
|
+
*/
|
|
247
|
+
getExemptionReason(categoryCode) {
|
|
248
|
+
const exemptionReasons = {
|
|
249
|
+
'E': 'Tax exempt',
|
|
250
|
+
'Z': 'Zero rated',
|
|
251
|
+
'AE': 'Reverse charge (§13b UStG)',
|
|
252
|
+
'K': 'Intra-EU supply',
|
|
253
|
+
'G': 'Export outside EU',
|
|
254
|
+
'O': 'Outside scope of tax',
|
|
255
|
+
'S': undefined // Standard rate, no exemption
|
|
256
|
+
};
|
|
257
|
+
return exemptionReasons[categoryCode];
|
|
258
|
+
}
|
|
259
|
+
/**
|
|
260
|
+
* Map VAT breakdown
|
|
261
|
+
*/
|
|
262
|
+
mapVATBreakdown(vatBreakdown) {
|
|
263
|
+
return vatBreakdown.map(vat => ({
|
|
264
|
+
vatCategory: this.mapVATCategory(vat.BT118_VATCategory, vat.BT119_VATRate),
|
|
265
|
+
taxableAmount: parseFloat(vat.BT116_TaxableAmount || 0),
|
|
266
|
+
taxAmount: parseFloat(vat.BT117_TaxAmount || 0)
|
|
267
|
+
}));
|
|
268
|
+
}
|
|
269
|
+
/**
|
|
270
|
+
* Map allowances and charges
|
|
271
|
+
*/
|
|
272
|
+
mapAllowancesCharges(data, isAllowance) {
|
|
273
|
+
return data.map(item => ({
|
|
274
|
+
reason: item.BT97_AllowanceReason || item.BT104_ChargeReason || '',
|
|
275
|
+
amount: parseFloat(item.BT92_AllowanceAmount || item.BT99_ChargeAmount || 0),
|
|
276
|
+
percentage: item.BT94_AllowancePercentage || item.BT101_ChargePercentage,
|
|
277
|
+
vatCategory: item.BT95_AllowanceVATCategory || item.BT102_ChargeVATCategory
|
|
278
|
+
? this.mapVATCategory(item.BT95_AllowanceVATCategory || item.BT102_ChargeVATCategory, item.BT96_AllowanceVATRate || item.BT103_ChargeVATRate)
|
|
279
|
+
: undefined,
|
|
280
|
+
vatAmount: parseFloat(item.allowanceVATAmount || item.chargeVATAmount || 0)
|
|
281
|
+
}));
|
|
282
|
+
}
|
|
283
|
+
/**
|
|
284
|
+
* Map line-level allowances and charges
|
|
285
|
+
*/
|
|
286
|
+
mapLineAllowancesCharges(data, isAllowance) {
|
|
287
|
+
return data.map(item => ({
|
|
288
|
+
reason: item.BT140_LineAllowanceReason || item.BT145_LineChargeReason || '',
|
|
289
|
+
amount: parseFloat(item.BT136_LineAllowanceAmount || item.BT141_LineChargeAmount || 0),
|
|
290
|
+
percentage: item.BT138_LineAllowancePercentage || item.BT143_LineChargePercentage
|
|
291
|
+
}));
|
|
292
|
+
}
|
|
293
|
+
/**
|
|
294
|
+
* Map payment terms
|
|
295
|
+
*/
|
|
296
|
+
mapPaymentTerms(businessTerms) {
|
|
297
|
+
if (!businessTerms.BT9_PaymentDueDate && !businessTerms.BT20_PaymentTerms) {
|
|
298
|
+
return undefined;
|
|
299
|
+
}
|
|
300
|
+
const paymentTerms = {
|
|
301
|
+
dueDate: businessTerms.BT9_PaymentDueDate
|
|
302
|
+
? new Date(businessTerms.BT9_PaymentDueDate)
|
|
303
|
+
: new Date(Date.now() + 30 * 24 * 60 * 60 * 1000), // Default 30 days
|
|
304
|
+
paymentTermsNote: businessTerms.BT20_PaymentTerms
|
|
305
|
+
};
|
|
306
|
+
// Parse skonto from payment terms note if present
|
|
307
|
+
if (businessTerms.BT20_PaymentTerms) {
|
|
308
|
+
paymentTerms.skonto = this.parseSkontoTerms(businessTerms.BT20_PaymentTerms);
|
|
309
|
+
}
|
|
310
|
+
return paymentTerms;
|
|
311
|
+
}
|
|
312
|
+
/**
|
|
313
|
+
* Parse skonto terms from payment terms text
|
|
314
|
+
*/
|
|
315
|
+
parseSkontoTerms(paymentTermsText) {
|
|
316
|
+
const skontoTerms = [];
|
|
317
|
+
// Common German skonto patterns:
|
|
318
|
+
// "2% Skonto bei Zahlung innerhalb von 10 Tagen"
|
|
319
|
+
// "3% bei Zahlung bis 8 Tage, 2% bis 14 Tage"
|
|
320
|
+
const skontoPattern = /(\d+(?:\.\d+)?)\s*%.*?(\d+)\s*(?:Tag|Day)/gi;
|
|
321
|
+
let match;
|
|
322
|
+
while ((match = skontoPattern.exec(paymentTermsText)) !== null) {
|
|
323
|
+
skontoTerms.push({
|
|
324
|
+
percentage: parseFloat(match[1]),
|
|
325
|
+
days: parseInt(match[2]),
|
|
326
|
+
baseAmount: 0 // To be calculated based on invoice amount
|
|
327
|
+
});
|
|
328
|
+
}
|
|
329
|
+
return skontoTerms.length > 0 ? skontoTerms : undefined;
|
|
330
|
+
}
|
|
331
|
+
/**
|
|
332
|
+
* Map payment means
|
|
333
|
+
*/
|
|
334
|
+
mapPaymentMeans(paymentInstructions) {
|
|
335
|
+
if (!paymentInstructions) {
|
|
336
|
+
return undefined;
|
|
337
|
+
}
|
|
338
|
+
return {
|
|
339
|
+
code: paymentInstructions.BT81_PaymentMeansCode || '30', // 30 = Bank transfer
|
|
340
|
+
account: paymentInstructions.BT84_PaymentAccountID
|
|
341
|
+
? {
|
|
342
|
+
iban: paymentInstructions.BT84_PaymentAccountID,
|
|
343
|
+
bic: paymentInstructions.BT86_PaymentServiceProviderID,
|
|
344
|
+
accountHolder: paymentInstructions.BT85_PaymentAccountName
|
|
345
|
+
}
|
|
346
|
+
: undefined
|
|
347
|
+
};
|
|
348
|
+
}
|
|
349
|
+
/**
|
|
350
|
+
* Classify tax scenario based on invoice data
|
|
351
|
+
*/
|
|
352
|
+
classifyTaxScenario(invoice) {
|
|
353
|
+
const supplierCountry = invoice.supplier.address.countryCode;
|
|
354
|
+
const customerCountry = invoice.customer.address.countryCode;
|
|
355
|
+
const hasVAT = invoice.totalVATAmount > 0;
|
|
356
|
+
const vatCategories = invoice.vatBreakdown.map(vb => vb.vatCategory.code);
|
|
357
|
+
// Reverse charge
|
|
358
|
+
if (vatCategories.includes('AE')) {
|
|
359
|
+
return 'reverse_charge';
|
|
360
|
+
}
|
|
361
|
+
// Small business exemption
|
|
362
|
+
if (vatCategories.includes('E') && invoice.invoiceNote?.includes('§19')) {
|
|
363
|
+
return 'small_business';
|
|
364
|
+
}
|
|
365
|
+
// Export outside EU
|
|
366
|
+
if (vatCategories.includes('G') || (!this.isEUCountry(customerCountry) && supplierCountry === 'DE')) {
|
|
367
|
+
return 'export';
|
|
368
|
+
}
|
|
369
|
+
// Intra-EU transactions
|
|
370
|
+
if (supplierCountry !== customerCountry && this.isEUCountry(supplierCountry) && this.isEUCountry(customerCountry)) {
|
|
371
|
+
if (invoice.direction === 'outbound') {
|
|
372
|
+
return 'intra_eu_supply';
|
|
373
|
+
}
|
|
374
|
+
else {
|
|
375
|
+
return 'intra_eu_acquisition';
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
// Domestic exempt
|
|
379
|
+
if (!hasVAT && supplierCountry === 'DE' && customerCountry === 'DE') {
|
|
380
|
+
return 'domestic_exempt';
|
|
381
|
+
}
|
|
382
|
+
// Default: Domestic taxed
|
|
383
|
+
return 'domestic_taxed';
|
|
384
|
+
}
|
|
385
|
+
/**
|
|
386
|
+
* Check if country is in EU
|
|
387
|
+
*/
|
|
388
|
+
isEUCountry(countryCode) {
|
|
389
|
+
const euCountries = [
|
|
390
|
+
'AT', 'BE', 'BG', 'HR', 'CY', 'CZ', 'DK', 'EE', 'FI', 'FR',
|
|
391
|
+
'DE', 'GR', 'HU', 'IE', 'IT', 'LV', 'LT', 'LU', 'MT', 'NL',
|
|
392
|
+
'PL', 'PT', 'RO', 'SK', 'SI', 'ES', 'SE'
|
|
393
|
+
];
|
|
394
|
+
return euCountries.includes(countryCode);
|
|
395
|
+
}
|
|
396
|
+
/**
|
|
397
|
+
* Map e-invoice format from library format
|
|
398
|
+
*/
|
|
399
|
+
mapEInvoiceFormat(format) {
|
|
400
|
+
const formatMap = {
|
|
401
|
+
'xrechnung': 'xrechnung',
|
|
402
|
+
'zugferd': 'zugferd',
|
|
403
|
+
'factur-x': 'facturx',
|
|
404
|
+
'facturx': 'facturx',
|
|
405
|
+
'peppol': 'peppol',
|
|
406
|
+
'ubl': 'ubl'
|
|
407
|
+
};
|
|
408
|
+
return formatMap[format.toLowerCase()] || 'xrechnung';
|
|
409
|
+
}
|
|
410
|
+
/**
|
|
411
|
+
* Calculate content hash for the invoice
|
|
412
|
+
*/
|
|
413
|
+
async calculateContentHash(xmlContent) {
|
|
414
|
+
const hash = await plugins.smarthash.sha256FromString(xmlContent);
|
|
415
|
+
return hash;
|
|
416
|
+
}
|
|
417
|
+
/**
|
|
418
|
+
* Convert invoice to different format
|
|
419
|
+
*/
|
|
420
|
+
async convertFormat(invoice, targetFormat) {
|
|
421
|
+
try {
|
|
422
|
+
// Load from existing XML
|
|
423
|
+
const einvoice = await plugins.einvoice.EInvoice.fromXml(invoice.xmlContent);
|
|
424
|
+
// Convert to target format (takes ~0.6ms)
|
|
425
|
+
const convertedXml = await einvoice.exportXml(targetFormat);
|
|
426
|
+
return convertedXml;
|
|
427
|
+
}
|
|
428
|
+
catch (error) {
|
|
429
|
+
this.logger.log('error', `Failed to convert invoice format: ${error}`);
|
|
430
|
+
throw new Error(`Format conversion failed: ${error.message}`);
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
/**
|
|
434
|
+
* Generate invoice from internal data
|
|
435
|
+
*/
|
|
436
|
+
async generateInvoice(invoiceData, format) {
|
|
437
|
+
try {
|
|
438
|
+
// Create a new invoice instance
|
|
439
|
+
const einvoice = new plugins.einvoice.EInvoice();
|
|
440
|
+
// Set invoice data
|
|
441
|
+
const businessTerms = this.mapToBusinessTerms(invoiceData);
|
|
442
|
+
Object.assign(einvoice, businessTerms);
|
|
443
|
+
// Generate XML in requested format
|
|
444
|
+
const xml = await einvoice.exportXml(format);
|
|
445
|
+
// Generate PDF if ZUGFeRD or Factur-X
|
|
446
|
+
let pdf;
|
|
447
|
+
if (format === 'zugferd' || format === 'facturx') {
|
|
448
|
+
// Access the pdf property if it exists
|
|
449
|
+
if (einvoice.pdf && einvoice.pdf.buffer) {
|
|
450
|
+
pdf = Buffer.from(einvoice.pdf.buffer);
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
return { xml, pdf };
|
|
454
|
+
}
|
|
455
|
+
catch (error) {
|
|
456
|
+
this.logger.log('error', `Failed to generate invoice: ${error}`);
|
|
457
|
+
throw new Error(`Invoice generation failed: ${error.message}`);
|
|
458
|
+
}
|
|
459
|
+
}
|
|
460
|
+
/**
|
|
461
|
+
* Map internal invoice to EN16931 Business Terms
|
|
462
|
+
*/
|
|
463
|
+
mapToBusinessTerms(invoice) {
|
|
464
|
+
return {
|
|
465
|
+
BT1_InvoiceNumber: invoice.invoiceNumber,
|
|
466
|
+
BT2_IssueDate: invoice.issueDate?.toISOString(),
|
|
467
|
+
BT3_InvoiceTypeCode: invoice.invoiceTypeCode || '380',
|
|
468
|
+
BT5_CurrencyCode: invoice.currencyCode || 'EUR',
|
|
469
|
+
BT7_TaxPointDate: invoice.taxPointDate?.toISOString(),
|
|
470
|
+
BT9_PaymentDueDate: invoice.paymentDueDate?.toISOString(),
|
|
471
|
+
// Map other Business Terms...
|
|
472
|
+
// This would be a comprehensive mapping in production
|
|
473
|
+
};
|
|
474
|
+
}
|
|
475
|
+
}
|
|
476
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2tyLmludm9pY2UuYWRhcHRlci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3RzL3Nrci5pbnZvaWNlLmFkYXB0ZXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxLQUFLLE9BQU8sTUFBTSxjQUFjLENBQUM7QUFjeEM7OztHQUdHO0FBQ0gsTUFBTSxPQUFPLGNBQWM7SUFHekI7UUFJaUIsaUJBQVksR0FBRyxFQUFFLEdBQUcsSUFBSSxHQUFHLElBQUksQ0FBQyxDQUFDLFdBQVc7UUFDNUMsaUJBQVksR0FBRyxFQUFFLEdBQUcsSUFBSSxHQUFHLElBQUksQ0FBQyxDQUFDLFdBQVc7UUFKM0QsSUFBSSxDQUFDLE1BQU0sR0FBRyxJQUFJLE9BQU8sQ0FBQyxRQUFRLENBQUMsVUFBVSxFQUFFLENBQUM7SUFDbEQsQ0FBQztJQUtEOztPQUVHO0lBQ0ksS0FBSyxDQUFDLFlBQVksQ0FDdkIsSUFBcUIsRUFDckIsU0FBNEI7UUFFNUIsSUFBSSxDQUFDO1lBQ0gsc0JBQXNCO1lBQ3RCLElBQUksTUFBTSxDQUFDLFFBQVEsQ0FBQyxJQUFJLENBQUMsRUFBRSxDQUFDO2dCQUMxQixJQUFJLElBQUksQ0FBQyxNQUFNLEdBQUcsSUFBSSxDQUFDLFlBQVksRUFBRSxDQUFDO29CQUNwQyxNQUFNLElBQUksS0FBSyxDQUFDLDJCQUEyQixJQUFJLENBQUMsTUFBTSxlQUFlLElBQUksQ0FBQyxZQUFZLFNBQVMsQ0FBQyxDQUFDO2dCQUNuRyxDQUFDO1lBQ0gsQ0FBQztpQkFBTSxJQUFJLE9BQU8sSUFBSSxLQUFLLFFBQVEsSUFBSSxJQUFJLENBQUMsTUFBTSxHQUFHLElBQUksQ0FBQyxZQUFZLEVBQUUsQ0FBQztnQkFDdkUsTUFBTSxJQUFJLEtBQUssQ0FBQywwQkFBMEIsSUFBSSxDQUFDLE1BQU0sb0JBQW9CLElBQUksQ0FBQyxZQUFZLGNBQWMsQ0FBQyxDQUFDO1lBQzVHLENBQUM7WUFFRCwyQ0FBMkM7WUFDM0MsSUFBSSxRQUFRLENBQUM7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
|