@fin.cx/skr 1.1.0 → 1.2.1
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.d.ts +8 -0
- package/dist_ts/00_commitinfo_data.js +9 -0
- 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.classes.account.d.ts +28 -0
- package/dist_ts/skr.classes.account.js +87 -4
- package/dist_ts/skr.classes.journalentry.js +56 -4
- package/dist_ts/skr.classes.ledger.js +5 -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 +578 -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.postingkeys.d.ts +56 -0
- package/dist_ts/skr.postingkeys.js +196 -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 +19 -0
- package/dist_ts/skr03.data.js +3 -1
- package/dist_ts/skr04.data.js +3 -1
- package/package.json +17 -12
- package/readme.hints.md +54 -1
- package/readme.md +207 -16
- package/ts/00_commitinfo_data.ts +8 -0
- package/ts/index.ts +6 -0
- package/ts/plugins.ts +22 -1
- package/ts/skr.api.ts +485 -0
- package/ts/skr.classes.account.ts +106 -3
- package/ts/skr.classes.journalentry.ts +78 -3
- package/ts/skr.classes.ledger.ts +4 -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 +760 -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.postingkeys.ts +252 -0
- package/ts/skr.security.ts +405 -0
- package/ts/skr.types.ts +27 -0
- package/ts/skr03.data.ts +2 -0
- package/ts/skr04.data.ts +2 -0
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* DATEV Posting Keys (Buchungsschlüssel) for German Accounting
|
|
3
|
+
*
|
|
4
|
+
* Posting keys control automatic VAT booking and are automatically checked
|
|
5
|
+
* in German tax audits (Betriebsprüfungen). Using incorrect posting keys
|
|
6
|
+
* can have serious tax consequences.
|
|
7
|
+
*
|
|
8
|
+
* Reference: DATEV Buchungsschlüssel-Verzeichnis
|
|
9
|
+
*/
|
|
10
|
+
/**
|
|
11
|
+
* Posting key definitions with validation rules
|
|
12
|
+
*/
|
|
13
|
+
export const POSTING_KEY_RULES = {
|
|
14
|
+
3: {
|
|
15
|
+
key: 3,
|
|
16
|
+
description: 'Zahlungseingang mit 19% Umsatzsteuer',
|
|
17
|
+
vatRate: 19,
|
|
18
|
+
requiresVAT: true,
|
|
19
|
+
disablesVATAutomatism: false,
|
|
20
|
+
allowedScenarios: ['domestic_taxed']
|
|
21
|
+
},
|
|
22
|
+
8: {
|
|
23
|
+
key: 8,
|
|
24
|
+
description: '7% Vorsteuer',
|
|
25
|
+
vatRate: 7,
|
|
26
|
+
requiresVAT: true,
|
|
27
|
+
disablesVATAutomatism: false,
|
|
28
|
+
allowedScenarios: ['domestic_taxed']
|
|
29
|
+
},
|
|
30
|
+
9: {
|
|
31
|
+
key: 9,
|
|
32
|
+
description: '19% Vorsteuer',
|
|
33
|
+
vatRate: 19,
|
|
34
|
+
requiresVAT: true,
|
|
35
|
+
disablesVATAutomatism: false,
|
|
36
|
+
allowedScenarios: ['domestic_taxed']
|
|
37
|
+
},
|
|
38
|
+
19: {
|
|
39
|
+
key: 19,
|
|
40
|
+
description: '19% Vorsteuer bei innergemeinschaftlichen Lieferungen',
|
|
41
|
+
vatRate: 19,
|
|
42
|
+
requiresVAT: true,
|
|
43
|
+
disablesVATAutomatism: false,
|
|
44
|
+
allowedScenarios: ['intra_eu']
|
|
45
|
+
},
|
|
46
|
+
40: {
|
|
47
|
+
key: 40,
|
|
48
|
+
description: 'Steuerfrei / Aufhebung der Automatik',
|
|
49
|
+
vatRate: 0,
|
|
50
|
+
requiresVAT: false,
|
|
51
|
+
disablesVATAutomatism: true,
|
|
52
|
+
allowedScenarios: ['tax_free', 'export', 'reverse_charge']
|
|
53
|
+
},
|
|
54
|
+
94: {
|
|
55
|
+
key: 94,
|
|
56
|
+
description: '19% Vorsteuer/Umsatzsteuer bei Erwerb aus EU oder Drittland (Reverse Charge)',
|
|
57
|
+
vatRate: 19,
|
|
58
|
+
requiresVAT: true,
|
|
59
|
+
disablesVATAutomatism: false,
|
|
60
|
+
allowedScenarios: ['reverse_charge', 'intra_eu', 'third_country']
|
|
61
|
+
}
|
|
62
|
+
};
|
|
63
|
+
/**
|
|
64
|
+
* Validate posting key for a journal entry line
|
|
65
|
+
*/
|
|
66
|
+
export function validatePostingKey(postingKey, accountNumber, amount, vatAmount, taxScenario) {
|
|
67
|
+
const errors = [];
|
|
68
|
+
const warnings = [];
|
|
69
|
+
// Get posting key rule
|
|
70
|
+
const rule = POSTING_KEY_RULES[postingKey];
|
|
71
|
+
if (!rule) {
|
|
72
|
+
errors.push(`Invalid posting key: ${postingKey}`);
|
|
73
|
+
return { isValid: false, errors, warnings };
|
|
74
|
+
}
|
|
75
|
+
// Validate VAT requirement
|
|
76
|
+
// Skip VAT amount requirement if:
|
|
77
|
+
// 1. Posting TO a VAT account (the line itself IS the VAT)
|
|
78
|
+
// 2. Posting TO a debtor/creditor account (receivable/payable settlement - VAT was already recorded)
|
|
79
|
+
const isVATAccount = accountNumber === '1571' || accountNumber === '1771' || accountNumber === '1576';
|
|
80
|
+
const accountNum = parseInt(accountNumber);
|
|
81
|
+
const isDebtorCreditorAccount = (accountNum >= 10000 && accountNum <= 69999) || (accountNum >= 70000 && accountNum <= 99999);
|
|
82
|
+
if (rule.requiresVAT && !vatAmount && !isVATAccount && !isDebtorCreditorAccount) {
|
|
83
|
+
errors.push(`Posting key ${postingKey} requires VAT amount, but none provided. ` +
|
|
84
|
+
`Description: ${rule.description}`);
|
|
85
|
+
}
|
|
86
|
+
// Validate VAT rate if specified
|
|
87
|
+
if (rule.vatRate && vatAmount && rule.vatRate > 0) {
|
|
88
|
+
const expectedVAT = Math.round(amount * rule.vatRate) / 100;
|
|
89
|
+
const tolerance = 0.02; // 2 cent tolerance for rounding
|
|
90
|
+
if (Math.abs(vatAmount - expectedVAT) > tolerance) {
|
|
91
|
+
warnings.push(`VAT amount ${vatAmount} does not match expected ${expectedVAT.toFixed(2)} ` +
|
|
92
|
+
`for posting key ${postingKey} (${rule.vatRate}%)`);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
// Validate tax scenario
|
|
96
|
+
if (rule.allowedScenarios && taxScenario) {
|
|
97
|
+
if (!rule.allowedScenarios.includes(taxScenario)) {
|
|
98
|
+
errors.push(`Posting key ${postingKey} is not valid for tax scenario '${taxScenario}'. ` +
|
|
99
|
+
`Allowed scenarios: ${rule.allowedScenarios.join(', ')}`);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
// Validate automatism disabling
|
|
103
|
+
if (rule.disablesVATAutomatism && vatAmount && vatAmount > 0) {
|
|
104
|
+
warnings.push(`Posting key ${postingKey} disables VAT automatism but VAT amount is provided. ` +
|
|
105
|
+
`This may cause incorrect tax reporting.`);
|
|
106
|
+
}
|
|
107
|
+
return {
|
|
108
|
+
isValid: errors.length === 0,
|
|
109
|
+
errors,
|
|
110
|
+
warnings
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Get posting key description
|
|
115
|
+
*/
|
|
116
|
+
export function getPostingKeyDescription(postingKey) {
|
|
117
|
+
const rule = POSTING_KEY_RULES[postingKey];
|
|
118
|
+
return rule ? rule.description : `Unknown posting key: ${postingKey}`;
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* Get appropriate posting key for a transaction
|
|
122
|
+
*/
|
|
123
|
+
export function suggestPostingKey(params) {
|
|
124
|
+
const { vatRate, taxScenario, isPayment } = params;
|
|
125
|
+
// Tax-free or reverse charge scenarios
|
|
126
|
+
if (taxScenario === 'tax_free' || taxScenario === 'export') {
|
|
127
|
+
return 40;
|
|
128
|
+
}
|
|
129
|
+
// Reverse charge
|
|
130
|
+
if (taxScenario === 'reverse_charge' || taxScenario === 'third_country') {
|
|
131
|
+
return 94;
|
|
132
|
+
}
|
|
133
|
+
// Intra-EU with VAT
|
|
134
|
+
if (taxScenario === 'intra_eu' && vatRate === 19) {
|
|
135
|
+
return 19;
|
|
136
|
+
}
|
|
137
|
+
// Payment with 19% VAT
|
|
138
|
+
if (isPayment && vatRate === 19) {
|
|
139
|
+
return 3;
|
|
140
|
+
}
|
|
141
|
+
// Input VAT based on rate
|
|
142
|
+
if (vatRate === 19) {
|
|
143
|
+
return 9;
|
|
144
|
+
}
|
|
145
|
+
if (vatRate === 7) {
|
|
146
|
+
return 8;
|
|
147
|
+
}
|
|
148
|
+
// Default to tax-free if no VAT
|
|
149
|
+
if (vatRate === 0) {
|
|
150
|
+
return 40;
|
|
151
|
+
}
|
|
152
|
+
// Fallback to 19% input VAT
|
|
153
|
+
return 9;
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* Validate all posting keys for consistency
|
|
157
|
+
*/
|
|
158
|
+
export function validatePostingKeyConsistency(lines) {
|
|
159
|
+
const errors = [];
|
|
160
|
+
const warnings = [];
|
|
161
|
+
// Check for mixing tax-free and taxed transactions
|
|
162
|
+
const hasTaxFree = lines.some(line => line.postingKey === 40);
|
|
163
|
+
const hasTaxed = lines.some(line => [3, 8, 9, 19, 94].includes(line.postingKey));
|
|
164
|
+
if (hasTaxFree && hasTaxed) {
|
|
165
|
+
warnings.push('Journal entry mixes tax-free (key 40) and taxed transactions. ' +
|
|
166
|
+
'Verify this is intentional.');
|
|
167
|
+
}
|
|
168
|
+
// Check for reverse charge consistency
|
|
169
|
+
const hasReverseCharge = lines.some(line => line.postingKey === 94);
|
|
170
|
+
if (hasReverseCharge) {
|
|
171
|
+
const reverseChargeLines = lines.filter(line => line.postingKey === 94);
|
|
172
|
+
if (reverseChargeLines.length % 2 !== 0) {
|
|
173
|
+
errors.push('Reverse charge (posting key 94) requires both input and output VAT entries. ' +
|
|
174
|
+
'Found odd number of reverse charge lines.');
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
return {
|
|
178
|
+
isValid: errors.length === 0,
|
|
179
|
+
errors,
|
|
180
|
+
warnings
|
|
181
|
+
};
|
|
182
|
+
}
|
|
183
|
+
/**
|
|
184
|
+
* Check if posting key requires automatic VAT booking
|
|
185
|
+
*/
|
|
186
|
+
export function requiresAutomaticVAT(postingKey) {
|
|
187
|
+
const rule = POSTING_KEY_RULES[postingKey];
|
|
188
|
+
return rule ? !rule.disablesVATAutomatism : false;
|
|
189
|
+
}
|
|
190
|
+
/**
|
|
191
|
+
* Get all valid posting keys
|
|
192
|
+
*/
|
|
193
|
+
export function getAllPostingKeys() {
|
|
194
|
+
return Object.keys(POSTING_KEY_RULES).map(k => Number(k));
|
|
195
|
+
}
|
|
196
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2tyLnBvc3RpbmdrZXlzLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vdHMvc2tyLnBvc3RpbmdrZXlzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOzs7Ozs7OztHQVFHO0FBSUg7O0dBRUc7QUFDSCxNQUFNLENBQUMsTUFBTSxpQkFBaUIsR0FBeUM7SUFDckUsQ0FBQyxFQUFFO1FBQ0QsR0FBRyxFQUFFLENBQUM7UUFDTixXQUFXLEVBQUUsc0NBQXNDO1FBQ25ELE9BQU8sRUFBRSxFQUFFO1FBQ1gsV0FBVyxFQUFFLElBQUk7UUFDakIscUJBQXFCLEVBQUUsS0FBSztRQUM1QixnQkFBZ0IsRUFBRSxDQUFDLGdCQUFnQixDQUFDO0tBQ3JDO0lBQ0QsQ0FBQyxFQUFFO1FBQ0QsR0FBRyxFQUFFLENBQUM7UUFDTixXQUFXLEVBQUUsY0FBYztRQUMzQixPQUFPLEVBQUUsQ0FBQztRQUNWLFdBQVcsRUFBRSxJQUFJO1FBQ2pCLHFCQUFxQixFQUFFLEtBQUs7UUFDNUIsZ0JBQWdCLEVBQUUsQ0FBQyxnQkFBZ0IsQ0FBQztLQUNyQztJQUNELENBQUMsRUFBRTtRQUNELEdBQUcsRUFBRSxDQUFDO1FBQ04sV0FBVyxFQUFFLGVBQWU7UUFDNUIsT0FBTyxFQUFFLEVBQUU7UUFDWCxXQUFXLEVBQUUsSUFBSTtRQUNqQixxQkFBcUIsRUFBRSxLQUFLO1FBQzVCLGdCQUFnQixFQUFFLENBQUMsZ0JBQWdCLENBQUM7S0FDckM7SUFDRCxFQUFFLEVBQUU7UUFDRixHQUFHLEVBQUUsRUFBRTtRQUNQLFdBQVcsRUFBRSx1REFBdUQ7UUFDcEUsT0FBTyxFQUFFLEVBQUU7UUFDWCxXQUFXLEVBQUUsSUFBSTtRQUNqQixxQkFBcUIsRUFBRSxLQUFLO1FBQzVCLGdCQUFnQixFQUFFLENBQUMsVUFBVSxDQUFDO0tBQy9CO0lBQ0QsRUFBRSxFQUFFO1FBQ0YsR0FBRyxFQUFFLEVBQUU7UUFDUCxXQUFXLEVBQUUsc0NBQXNDO1FBQ25ELE9BQU8sRUFBRSxDQUFD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
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
export interface ISigningOptions {
|
|
2
|
+
certificatePem?: string;
|
|
3
|
+
privateKeyPem?: string;
|
|
4
|
+
privateKeyPassphrase?: string;
|
|
5
|
+
timestampServerUrl?: string;
|
|
6
|
+
includeTimestamp?: boolean;
|
|
7
|
+
}
|
|
8
|
+
export interface ISignatureResult {
|
|
9
|
+
signature: string;
|
|
10
|
+
signatureFormat: 'CAdES-B' | 'CAdES-T' | 'CAdES-LT';
|
|
11
|
+
signingTime: string;
|
|
12
|
+
certificateChain?: string[];
|
|
13
|
+
timestampToken?: string;
|
|
14
|
+
timestampTime?: string;
|
|
15
|
+
}
|
|
16
|
+
export interface ITimestampResponse {
|
|
17
|
+
token: string;
|
|
18
|
+
time: string;
|
|
19
|
+
serverUrl: string;
|
|
20
|
+
hashAlgorithm: string;
|
|
21
|
+
}
|
|
22
|
+
export declare class SecurityManager {
|
|
23
|
+
private options;
|
|
24
|
+
private logger;
|
|
25
|
+
constructor(options?: ISigningOptions);
|
|
26
|
+
/**
|
|
27
|
+
* Creates a CAdES-B (Basic) signature for data
|
|
28
|
+
*/
|
|
29
|
+
createCadesSignature(data: Buffer | string, certificatePem?: string, privateKeyPem?: string): Promise<ISignatureResult>;
|
|
30
|
+
/**
|
|
31
|
+
* Requests an RFC 3161 timestamp from a TSA
|
|
32
|
+
*/
|
|
33
|
+
requestTimestamp(dataHash: string | Buffer): Promise<ITimestampResponse>;
|
|
34
|
+
/**
|
|
35
|
+
* Creates a timestamp request (simplified version)
|
|
36
|
+
*/
|
|
37
|
+
private createTimestampRequest;
|
|
38
|
+
/**
|
|
39
|
+
* Sends timestamp request to TSA server
|
|
40
|
+
*/
|
|
41
|
+
private sendTimestampRequest;
|
|
42
|
+
/**
|
|
43
|
+
* Verifies a CAdES signature
|
|
44
|
+
*/
|
|
45
|
+
verifyCadesSignature(data: Buffer | string, signature: string, certificatePem?: string): Promise<boolean>;
|
|
46
|
+
/**
|
|
47
|
+
* Generates a self-signed certificate for testing
|
|
48
|
+
*/
|
|
49
|
+
generateSelfSignedCertificate(commonName?: string, validDays?: number): Promise<{
|
|
50
|
+
certificate: string;
|
|
51
|
+
privateKey: string;
|
|
52
|
+
}>;
|
|
53
|
+
/**
|
|
54
|
+
* Creates a detached signature file
|
|
55
|
+
*/
|
|
56
|
+
createDetachedSignature(dataPath: string, outputPath: string): Promise<void>;
|
|
57
|
+
/**
|
|
58
|
+
* Verifies a detached signature file
|
|
59
|
+
*/
|
|
60
|
+
verifyDetachedSignature(dataPath: string, signaturePath: string): Promise<boolean>;
|
|
61
|
+
/**
|
|
62
|
+
* Adds Long-Term Validation (LTV) information
|
|
63
|
+
*/
|
|
64
|
+
addLtvInformation(signature: ISignatureResult, ocspResponse?: Buffer, crlData?: Buffer): Promise<ISignatureResult>;
|
|
65
|
+
}
|
|
@@ -0,0 +1,319 @@
|
|
|
1
|
+
import * as plugins from './plugins.js';
|
|
2
|
+
import * as path from 'path';
|
|
3
|
+
import * as crypto from 'crypto';
|
|
4
|
+
import * as https from 'https';
|
|
5
|
+
export class SecurityManager {
|
|
6
|
+
constructor(options = {}) {
|
|
7
|
+
this.options = {
|
|
8
|
+
timestampServerUrl: options.timestampServerUrl || 'http://timestamp.digicert.com',
|
|
9
|
+
includeTimestamp: options.includeTimestamp !== false,
|
|
10
|
+
...options
|
|
11
|
+
};
|
|
12
|
+
this.logger = new plugins.smartlog.ConsoleLog();
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Creates a CAdES-B (Basic) signature for data
|
|
16
|
+
*/
|
|
17
|
+
async createCadesSignature(data, certificatePem, privateKeyPem) {
|
|
18
|
+
const cert = certificatePem || this.options.certificatePem;
|
|
19
|
+
const key = privateKeyPem || this.options.privateKeyPem;
|
|
20
|
+
if (!cert || !key) {
|
|
21
|
+
throw new Error('Certificate and private key are required for signing');
|
|
22
|
+
}
|
|
23
|
+
try {
|
|
24
|
+
// Parse certificate and key
|
|
25
|
+
const certificate = plugins.nodeForge.pki.certificateFromPem(cert);
|
|
26
|
+
const privateKey = this.options.privateKeyPassphrase
|
|
27
|
+
? plugins.nodeForge.pki.decryptRsaPrivateKey(key, this.options.privateKeyPassphrase)
|
|
28
|
+
: plugins.nodeForge.pki.privateKeyFromPem(key);
|
|
29
|
+
// Create PKCS#7 signed data (CMS)
|
|
30
|
+
const p7 = plugins.nodeForge.pkcs7.createSignedData();
|
|
31
|
+
// Add content
|
|
32
|
+
if (typeof data === 'string') {
|
|
33
|
+
p7.content = plugins.nodeForge.util.createBuffer(data, 'utf8');
|
|
34
|
+
}
|
|
35
|
+
else {
|
|
36
|
+
p7.content = plugins.nodeForge.util.createBuffer(data.toString('latin1'));
|
|
37
|
+
}
|
|
38
|
+
// Add certificate
|
|
39
|
+
p7.addCertificate(certificate);
|
|
40
|
+
// Add signer
|
|
41
|
+
p7.addSigner({
|
|
42
|
+
key: privateKey,
|
|
43
|
+
certificate: certificate,
|
|
44
|
+
digestAlgorithm: plugins.nodeForge.pki.oids.sha256,
|
|
45
|
+
authenticatedAttributes: [
|
|
46
|
+
{
|
|
47
|
+
type: plugins.nodeForge.pki.oids.contentType,
|
|
48
|
+
value: plugins.nodeForge.pki.oids.data
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
type: plugins.nodeForge.pki.oids.messageDigest
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
type: plugins.nodeForge.pki.oids.signingTime,
|
|
55
|
+
value: new Date().toISOString()
|
|
56
|
+
}
|
|
57
|
+
]
|
|
58
|
+
});
|
|
59
|
+
// Sign the data
|
|
60
|
+
p7.sign({ detached: true });
|
|
61
|
+
// Convert to PEM
|
|
62
|
+
const pem = plugins.nodeForge.pkcs7.messageToPem(p7);
|
|
63
|
+
// Extract base64 signature
|
|
64
|
+
const signature = pem
|
|
65
|
+
.replace(/-----BEGIN PKCS7-----/, '')
|
|
66
|
+
.replace(/-----END PKCS7-----/, '')
|
|
67
|
+
.replace(/\r?\n/g, '');
|
|
68
|
+
const result = {
|
|
69
|
+
signature: signature,
|
|
70
|
+
signatureFormat: 'CAdES-B',
|
|
71
|
+
signingTime: new Date().toISOString(),
|
|
72
|
+
certificateChain: [cert]
|
|
73
|
+
};
|
|
74
|
+
// Add timestamp if requested
|
|
75
|
+
if (this.options.includeTimestamp && this.options.timestampServerUrl) {
|
|
76
|
+
try {
|
|
77
|
+
const timestampResponse = await this.requestTimestamp(signature);
|
|
78
|
+
result.timestampToken = timestampResponse.token;
|
|
79
|
+
result.timestampTime = timestampResponse.time;
|
|
80
|
+
result.signatureFormat = 'CAdES-T';
|
|
81
|
+
}
|
|
82
|
+
catch (error) {
|
|
83
|
+
this.logger.log('warn', `Failed to obtain timestamp: ${error}`);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
return result;
|
|
87
|
+
}
|
|
88
|
+
catch (error) {
|
|
89
|
+
throw new Error(`Failed to create CAdES signature: ${error}`);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Requests an RFC 3161 timestamp from a TSA
|
|
94
|
+
*/
|
|
95
|
+
async requestTimestamp(dataHash) {
|
|
96
|
+
try {
|
|
97
|
+
// Create hash of the data
|
|
98
|
+
let hash;
|
|
99
|
+
if (typeof dataHash === 'string') {
|
|
100
|
+
hash = crypto.createHash('sha256').update(dataHash).digest();
|
|
101
|
+
}
|
|
102
|
+
else {
|
|
103
|
+
hash = crypto.createHash('sha256').update(dataHash).digest();
|
|
104
|
+
}
|
|
105
|
+
// Create timestamp request (simplified - in production use proper ASN.1 encoding)
|
|
106
|
+
const tsRequest = this.createTimestampRequest(hash);
|
|
107
|
+
// Send request to TSA
|
|
108
|
+
const response = await this.sendTimestampRequest(tsRequest);
|
|
109
|
+
return {
|
|
110
|
+
token: response.toString('base64'),
|
|
111
|
+
time: new Date().toISOString(),
|
|
112
|
+
serverUrl: this.options.timestampServerUrl,
|
|
113
|
+
hashAlgorithm: 'sha256'
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
catch (error) {
|
|
117
|
+
throw new Error(`Failed to obtain timestamp: ${error}`);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* Creates a timestamp request (simplified version)
|
|
122
|
+
*/
|
|
123
|
+
createTimestampRequest(hash) {
|
|
124
|
+
// In production, use proper ASN.1 encoding library
|
|
125
|
+
// This is a simplified placeholder
|
|
126
|
+
const request = {
|
|
127
|
+
version: 1,
|
|
128
|
+
messageImprint: {
|
|
129
|
+
hashAlgorithm: { algorithm: '2.16.840.1.101.3.4.2.1' }, // SHA-256 OID
|
|
130
|
+
hashedMessage: hash
|
|
131
|
+
},
|
|
132
|
+
reqPolicy: null,
|
|
133
|
+
nonce: crypto.randomBytes(8),
|
|
134
|
+
certReq: true
|
|
135
|
+
};
|
|
136
|
+
// Convert to DER-encoded ASN.1 (simplified)
|
|
137
|
+
return Buffer.from(JSON.stringify(request));
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* Sends timestamp request to TSA server
|
|
141
|
+
*/
|
|
142
|
+
async sendTimestampRequest(request) {
|
|
143
|
+
return new Promise((resolve, reject) => {
|
|
144
|
+
const url = new URL(this.options.timestampServerUrl);
|
|
145
|
+
const options = {
|
|
146
|
+
hostname: url.hostname,
|
|
147
|
+
port: url.port || 443,
|
|
148
|
+
path: url.pathname,
|
|
149
|
+
method: 'POST',
|
|
150
|
+
headers: {
|
|
151
|
+
'Content-Type': 'application/timestamp-query',
|
|
152
|
+
'Content-Length': request.length
|
|
153
|
+
}
|
|
154
|
+
};
|
|
155
|
+
const req = https.request(options, (res) => {
|
|
156
|
+
const chunks = [];
|
|
157
|
+
res.on('data', (chunk) => chunks.push(chunk));
|
|
158
|
+
res.on('end', () => {
|
|
159
|
+
const response = Buffer.concat(chunks);
|
|
160
|
+
if (res.statusCode === 200) {
|
|
161
|
+
resolve(response);
|
|
162
|
+
}
|
|
163
|
+
else {
|
|
164
|
+
reject(new Error(`TSA server returned status ${res.statusCode}`));
|
|
165
|
+
}
|
|
166
|
+
});
|
|
167
|
+
});
|
|
168
|
+
req.on('error', reject);
|
|
169
|
+
req.write(request);
|
|
170
|
+
req.end();
|
|
171
|
+
});
|
|
172
|
+
}
|
|
173
|
+
/**
|
|
174
|
+
* Verifies a CAdES signature
|
|
175
|
+
*/
|
|
176
|
+
async verifyCadesSignature(data, signature, certificatePem) {
|
|
177
|
+
try {
|
|
178
|
+
// Add PEM headers if not present
|
|
179
|
+
let pemSignature = signature;
|
|
180
|
+
if (!signature.includes('BEGIN PKCS7')) {
|
|
181
|
+
pemSignature = `-----BEGIN PKCS7-----\n${signature}\n-----END PKCS7-----`;
|
|
182
|
+
}
|
|
183
|
+
// Parse the PKCS#7 message
|
|
184
|
+
const p7 = plugins.nodeForge.pkcs7.messageFromPem(pemSignature);
|
|
185
|
+
// Prepare content for verification
|
|
186
|
+
let content;
|
|
187
|
+
if (typeof data === 'string') {
|
|
188
|
+
content = plugins.nodeForge.util.createBuffer(data, 'utf8');
|
|
189
|
+
}
|
|
190
|
+
else {
|
|
191
|
+
content = plugins.nodeForge.util.createBuffer(data.toString('latin1'));
|
|
192
|
+
}
|
|
193
|
+
// Verify the signature
|
|
194
|
+
const verified = p7.verify({
|
|
195
|
+
content: content,
|
|
196
|
+
detached: true
|
|
197
|
+
});
|
|
198
|
+
return verified;
|
|
199
|
+
}
|
|
200
|
+
catch (error) {
|
|
201
|
+
this.logger.log('error', `Signature verification failed: ${error}`);
|
|
202
|
+
return false;
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
/**
|
|
206
|
+
* Generates a self-signed certificate for testing
|
|
207
|
+
*/
|
|
208
|
+
async generateSelfSignedCertificate(commonName = 'SKR Export System', validDays = 365) {
|
|
209
|
+
const keys = plugins.nodeForge.pki.rsa.generateKeyPair(2048);
|
|
210
|
+
const cert = plugins.nodeForge.pki.createCertificate();
|
|
211
|
+
cert.publicKey = keys.publicKey;
|
|
212
|
+
cert.serialNumber = '01';
|
|
213
|
+
cert.validity.notBefore = new Date();
|
|
214
|
+
cert.validity.notAfter = new Date();
|
|
215
|
+
cert.validity.notAfter.setDate(cert.validity.notAfter.getDate() + validDays);
|
|
216
|
+
const attrs = [
|
|
217
|
+
{ name: 'commonName', value: commonName },
|
|
218
|
+
{ name: 'countryName', value: 'DE' },
|
|
219
|
+
{ name: 'organizationName', value: 'SKR Export System' },
|
|
220
|
+
{ shortName: 'OU', value: 'Accounting' }
|
|
221
|
+
];
|
|
222
|
+
cert.setSubject(attrs);
|
|
223
|
+
cert.setIssuer(attrs);
|
|
224
|
+
cert.setExtensions([
|
|
225
|
+
{
|
|
226
|
+
name: 'basicConstraints',
|
|
227
|
+
cA: true
|
|
228
|
+
},
|
|
229
|
+
{
|
|
230
|
+
name: 'keyUsage',
|
|
231
|
+
keyCertSign: true,
|
|
232
|
+
digitalSignature: true,
|
|
233
|
+
nonRepudiation: true,
|
|
234
|
+
keyEncipherment: true,
|
|
235
|
+
dataEncipherment: true
|
|
236
|
+
},
|
|
237
|
+
{
|
|
238
|
+
name: 'extKeyUsage',
|
|
239
|
+
serverAuth: true,
|
|
240
|
+
clientAuth: true,
|
|
241
|
+
codeSigning: true,
|
|
242
|
+
emailProtection: true,
|
|
243
|
+
timeStamping: true
|
|
244
|
+
},
|
|
245
|
+
{
|
|
246
|
+
name: 'nsCertType',
|
|
247
|
+
client: true,
|
|
248
|
+
server: true,
|
|
249
|
+
email: true,
|
|
250
|
+
objsign: true,
|
|
251
|
+
sslCA: true,
|
|
252
|
+
emailCA: true,
|
|
253
|
+
objCA: true
|
|
254
|
+
},
|
|
255
|
+
{
|
|
256
|
+
name: 'subjectAltName',
|
|
257
|
+
altNames: [
|
|
258
|
+
{ type: 2, value: commonName }
|
|
259
|
+
]
|
|
260
|
+
}
|
|
261
|
+
]);
|
|
262
|
+
// Self-sign certificate
|
|
263
|
+
cert.sign(keys.privateKey, plugins.nodeForge.md.sha256.create());
|
|
264
|
+
// Convert to PEM
|
|
265
|
+
const certificatePem = plugins.nodeForge.pki.certificateToPem(cert);
|
|
266
|
+
const privateKeyPem = plugins.nodeForge.pki.privateKeyToPem(keys.privateKey);
|
|
267
|
+
return {
|
|
268
|
+
certificate: certificatePem,
|
|
269
|
+
privateKey: privateKeyPem
|
|
270
|
+
};
|
|
271
|
+
}
|
|
272
|
+
/**
|
|
273
|
+
* Creates a detached signature file
|
|
274
|
+
*/
|
|
275
|
+
async createDetachedSignature(dataPath, outputPath) {
|
|
276
|
+
const data = await plugins.smartfile.fs.toBuffer(dataPath);
|
|
277
|
+
const signature = await this.createCadesSignature(data);
|
|
278
|
+
const signatureData = {
|
|
279
|
+
signature: signature.signature,
|
|
280
|
+
format: signature.signatureFormat,
|
|
281
|
+
signingTime: signature.signingTime,
|
|
282
|
+
timestamp: signature.timestampToken,
|
|
283
|
+
timestampTime: signature.timestampTime,
|
|
284
|
+
algorithm: 'SHA256withRSA',
|
|
285
|
+
signedFile: path.basename(dataPath)
|
|
286
|
+
};
|
|
287
|
+
await plugins.smartfile.memory.toFs(JSON.stringify(signatureData, null, 2), outputPath);
|
|
288
|
+
}
|
|
289
|
+
/**
|
|
290
|
+
* Verifies a detached signature file
|
|
291
|
+
*/
|
|
292
|
+
async verifyDetachedSignature(dataPath, signaturePath) {
|
|
293
|
+
try {
|
|
294
|
+
const data = await plugins.smartfile.fs.toBuffer(dataPath);
|
|
295
|
+
const signatureJson = await plugins.smartfile.fs.toStringSync(signaturePath);
|
|
296
|
+
const signatureData = JSON.parse(signatureJson);
|
|
297
|
+
return await this.verifyCadesSignature(data, signatureData.signature);
|
|
298
|
+
}
|
|
299
|
+
catch (error) {
|
|
300
|
+
this.logger.log('error', `Failed to verify detached signature: ${error}`);
|
|
301
|
+
return false;
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
/**
|
|
305
|
+
* Adds Long-Term Validation (LTV) information
|
|
306
|
+
*/
|
|
307
|
+
async addLtvInformation(signature, ocspResponse, crlData) {
|
|
308
|
+
// Add OCSP response and CRL data for long-term validation
|
|
309
|
+
const ltv = {
|
|
310
|
+
...signature,
|
|
311
|
+
signatureFormat: 'CAdES-LT',
|
|
312
|
+
ocsp: ocspResponse?.toString('base64'),
|
|
313
|
+
crl: crlData?.toString('base64'),
|
|
314
|
+
ltvTime: new Date().toISOString()
|
|
315
|
+
};
|
|
316
|
+
return ltv;
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2tyLnNlY3VyaXR5LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vdHMvc2tyLnNlY3VyaXR5LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sS0FBSyxPQUFPLE1BQU0sY0FBYyxDQUFDO0FBQ3hDLE9BQU8sS0FBSyxJQUFJLE1BQU0sTUFBTSxDQUFDO0FBQzdCLE9BQU8sS0FBSyxNQUFNLE1BQU0sUUFBUSxDQUFDO0FBQ2pDLE9BQU8sS0FBSyxLQUFLLE1BQU0sT0FBTyxDQUFDO0FBMEIvQixNQUFNLE9BQU8sZUFBZTtJQUkxQixZQUFZLFVBQTJCLEVBQUU7UUFDdkMsSUFBSSxDQUFDLE9BQU8sR0FBRztZQUNiLGtCQUFrQixFQUFFLE9BQU8sQ0FBQyxrQkFBa0IsSUFBSSwrQkFBK0I7WUFDakYsZ0JBQWdCLEVBQUUsT0FBTyxDQUFDLGdCQUFnQixLQUFLLEtBQUs7WUFDcEQsR0FBRyxPQUFPO1NBQ1gsQ0FBQztRQUNGLElBQUksQ0FBQyxNQUFNLEdBQUcsSUFBSSxPQUFPLENBQUMsUUFBUSxDQUFDLFVBQVUsRUFBRSxDQUFDO0lBQ2xELENBQUM7SUFFRDs7T0FFRztJQUNJLEtBQUssQ0FBQyxvQkFBb0IsQ0FDL0IsSUFBcUIsRUFDckIsY0FBdUIsRUFDdkIsYUFBc0I7UUFFdEIsTUFBTSxJQUFJLEdBQUcsY0FBYyxJQUFJLElBQUksQ0FBQyxPQUFPLENBQUMsY0FBYyxDQUFDO1FBQzNELE1BQU0sR0FBRyxHQUFHLGFBQWEsSUFBSSxJQUFJLENBQUMsT0FBTyxDQUFDLGFBQWEsQ0FBQztRQUV4RCxJQUFJLENBQUMsSUFBSSxJQUFJLENBQUMsR0FBRyxFQUFFLENBQUM7WUFDbEIsTUFBTSxJQUFJLEtBQUssQ0FBQyxzREFBc0QsQ0FBQyxDQUFDO1FBQzFFLENBQUM7UUFFRCxJQUFJLENBQUM7WUFDSCw0QkFBNEI7WUFDNUIsTUFBTSxXQUFXLEdBQUcsT0FBTyxDQUFDLFNBQVMsQ0FBQyxHQUFHLENBQUMsa0JBQWtCLENBQUMs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
|
package/dist_ts/skr.types.d.ts
CHANGED
|
@@ -1,7 +1,23 @@
|
|
|
1
1
|
export type TAccountType = 'asset' | 'liability' | 'equity' | 'revenue' | 'expense';
|
|
2
2
|
export type TSKRType = 'SKR03' | 'SKR04';
|
|
3
3
|
export type TTransactionStatus = 'pending' | 'posted' | 'reversed';
|
|
4
|
+
/**
|
|
5
|
+
* DATEV posting keys (Buchungsschlüssel) for German accounting
|
|
6
|
+
* These keys control automatic VAT booking and are checked in tax audits
|
|
7
|
+
*/
|
|
8
|
+
export type TPostingKey = 3 | 8 | 9 | 19 | 40 | 94;
|
|
4
9
|
export type TReportType = 'trial_balance' | 'income_statement' | 'balance_sheet' | 'general_ledger' | 'cash_flow';
|
|
10
|
+
/**
|
|
11
|
+
* Posting key validation rule
|
|
12
|
+
*/
|
|
13
|
+
export interface IPostingKeyRule {
|
|
14
|
+
key: TPostingKey;
|
|
15
|
+
description: string;
|
|
16
|
+
vatRate?: number;
|
|
17
|
+
requiresVAT: boolean;
|
|
18
|
+
disablesVATAutomatism: boolean;
|
|
19
|
+
allowedScenarios?: string[];
|
|
20
|
+
}
|
|
5
21
|
export interface IAccountData {
|
|
6
22
|
accountNumber: string;
|
|
7
23
|
accountName: string;
|
|
@@ -11,6 +27,7 @@ export interface IAccountData {
|
|
|
11
27
|
description?: string;
|
|
12
28
|
vatRate?: number;
|
|
13
29
|
isActive?: boolean;
|
|
30
|
+
isAutomaticAccount?: boolean;
|
|
14
31
|
}
|
|
15
32
|
export interface ITransactionData {
|
|
16
33
|
date: Date;
|
|
@@ -36,6 +53,7 @@ export interface IJournalEntryLine {
|
|
|
36
53
|
credit?: number;
|
|
37
54
|
description?: string;
|
|
38
55
|
costCenter?: string;
|
|
56
|
+
postingKey: TPostingKey;
|
|
39
57
|
}
|
|
40
58
|
export interface ITrialBalanceEntry {
|
|
41
59
|
accountNumber: string;
|
|
@@ -110,6 +128,7 @@ export interface ITransactionFilter {
|
|
|
110
128
|
export interface IDatabaseConfig {
|
|
111
129
|
mongoDbUrl: string;
|
|
112
130
|
dbName?: string;
|
|
131
|
+
invoiceExportPath?: string;
|
|
113
132
|
}
|
|
114
133
|
export interface IReportParams {
|
|
115
134
|
dateFrom?: Date;
|