@fin.cx/skr 1.2.1 → 1.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (46) hide show
  1. package/{npmextra.json → .smartconfig.json} +12 -6
  2. package/dist_ts/00_commitinfo_data.js +1 -1
  3. package/dist_ts/index.d.ts +21 -15
  4. package/dist_ts/index.js +16 -16
  5. package/dist_ts/plugins.d.ts +15 -5
  6. package/dist_ts/plugins.js +42 -6
  7. package/dist_ts/skr.api.js +20 -13
  8. package/dist_ts/skr.classes.account.d.ts +8 -3
  9. package/dist_ts/skr.classes.account.js +358 -285
  10. package/dist_ts/skr.classes.chartofaccounts.d.ts +1 -1
  11. package/dist_ts/skr.classes.chartofaccounts.js +13 -6
  12. package/dist_ts/skr.classes.journalentry.d.ts +9 -4
  13. package/dist_ts/skr.classes.journalentry.js +424 -355
  14. package/dist_ts/skr.classes.ledger.js +3 -1
  15. package/dist_ts/skr.classes.reports.js +4 -1
  16. package/dist_ts/skr.classes.transaction.d.ts +9 -4
  17. package/dist_ts/skr.classes.transaction.js +315 -244
  18. package/dist_ts/skr.export.accounts.js +3 -2
  19. package/dist_ts/skr.export.balances.js +4 -2
  20. package/dist_ts/skr.export.js +6 -3
  21. package/dist_ts/skr.export.ledger.js +4 -3
  22. package/dist_ts/skr.export.pdf.js +6 -3
  23. package/dist_ts/skr.invoice.adapter.d.ts +2 -0
  24. package/dist_ts/skr.invoice.adapter.js +22 -10
  25. package/dist_ts/skr.invoice.booking.js +8 -3
  26. package/dist_ts/skr.invoice.mapper.js +84 -82
  27. package/dist_ts/skr.invoice.storage.js +10 -5
  28. package/dist_ts/skr.security.js +24 -21
  29. package/license.md +21 -0
  30. package/package.json +31 -23
  31. package/readme.md +215 -632
  32. package/readme.plan.md +1 -1
  33. package/ts/00_commitinfo_data.ts +1 -1
  34. package/ts/index.ts +43 -15
  35. package/ts/plugins.ts +52 -15
  36. package/ts/skr.api.ts +9 -5
  37. package/ts/skr.classes.account.ts +39 -21
  38. package/ts/skr.classes.chartofaccounts.ts +8 -3
  39. package/ts/skr.classes.journalentry.ts +40 -22
  40. package/ts/skr.classes.reports.ts +22 -2
  41. package/ts/skr.classes.transaction.ts +40 -22
  42. package/ts/skr.export.pdf.ts +4 -3
  43. package/ts/skr.invoice.adapter.ts +31 -11
  44. package/ts/skr.invoice.booking.ts +5 -3
  45. package/ts/skr.invoice.storage.ts +3 -2
  46. package/ts/skr.security.ts +23 -22
@@ -18,11 +18,25 @@ import type {
18
18
  */
19
19
  export class InvoiceAdapter {
20
20
  private logger: plugins.smartlog.ConsoleLog;
21
+ private readonly einvoiceModuleName = '@fin.cx/einvoice';
21
22
 
22
23
  constructor() {
23
24
  this.logger = new plugins.smartlog.ConsoleLog();
24
25
  }
25
26
 
27
+ private async getEInvoiceClass(): Promise<{
28
+ new (): any;
29
+ fromXml(xmlString: string): Promise<any>;
30
+ }> {
31
+ const { EInvoice } = (await import(this.einvoiceModuleName)) as {
32
+ EInvoice: {
33
+ new (): any;
34
+ fromXml(xmlString: string): Promise<any>;
35
+ };
36
+ };
37
+ return EInvoice;
38
+ }
39
+
26
40
  private readonly MAX_XML_SIZE = 10 * 1024 * 1024; // 10MB max
27
41
  private readonly MAX_PDF_SIZE = 50 * 1024 * 1024; // 50MB max
28
42
 
@@ -44,13 +58,14 @@ export class InvoiceAdapter {
44
58
  }
45
59
 
46
60
  // Parse the invoice using @fin.cx/einvoice
47
- let einvoice;
61
+ const EInvoice = await this.getEInvoiceClass();
62
+ let einvoice: any;
48
63
  if (typeof file === 'string') {
49
- einvoice = await plugins.einvoice.EInvoice.fromXml(file);
64
+ einvoice = await EInvoice.fromXml(file);
50
65
  } else {
51
66
  // Convert buffer to string first
52
67
  const xmlString = file.toString('utf-8');
53
- einvoice = await plugins.einvoice.EInvoice.fromXml(xmlString);
68
+ einvoice = await EInvoice.fromXml(xmlString);
54
69
  }
55
70
 
56
71
  // Get detected format
@@ -74,7 +89,7 @@ export class InvoiceAdapter {
74
89
  invoice.xmlContent = einvoice.getXml();
75
90
 
76
91
  // Calculate content hash
77
- invoice.contentHash = await this.calculateContentHash(invoice.xmlContent);
92
+ invoice.contentHash = await this.calculateContentHash(invoice.xmlContent!);
78
93
 
79
94
  // Classify tax scenario
80
95
  invoice.taxScenario = this.classifyTaxScenario(invoice);
@@ -82,7 +97,8 @@ export class InvoiceAdapter {
82
97
  return invoice;
83
98
  } catch (error) {
84
99
  this.logger.log('error', `Failed to parse invoice: ${error}`);
85
- throw new Error(`Invoice parsing failed: ${error.message}`);
100
+ const errorMessage = error instanceof Error ? error.message : String(error);
101
+ throw new Error(`Invoice parsing failed: ${errorMessage}`);
86
102
  }
87
103
  }
88
104
 
@@ -310,7 +326,7 @@ export class InvoiceAdapter {
310
326
  * Get exemption reason for VAT category
311
327
  */
312
328
  private getExemptionReason(categoryCode: string): string | undefined {
313
- const exemptionReasons: Record<string, string> = {
329
+ const exemptionReasons: Record<string, string | undefined> = {
314
330
  'E': 'Tax exempt',
315
331
  'Z': 'Zero rated',
316
332
  'AE': 'Reverse charge (§13b UStG)',
@@ -516,7 +532,8 @@ export class InvoiceAdapter {
516
532
  ): Promise<string> {
517
533
  try {
518
534
  // Load from existing XML
519
- const einvoice = await plugins.einvoice.EInvoice.fromXml(invoice.xmlContent!);
535
+ const EInvoice = await this.getEInvoiceClass();
536
+ const einvoice: any = await EInvoice.fromXml(invoice.xmlContent!);
520
537
 
521
538
  // Convert to target format (takes ~0.6ms)
522
539
  const convertedXml = await einvoice.exportXml(targetFormat as any);
@@ -524,7 +541,8 @@ export class InvoiceAdapter {
524
541
  return convertedXml;
525
542
  } catch (error) {
526
543
  this.logger.log('error', `Failed to convert invoice format: ${error}`);
527
- throw new Error(`Format conversion failed: ${error.message}`);
544
+ const errorMessage = error instanceof Error ? error.message : String(error);
545
+ throw new Error(`Format conversion failed: ${errorMessage}`);
528
546
  }
529
547
  }
530
548
 
@@ -537,7 +555,8 @@ export class InvoiceAdapter {
537
555
  ): Promise<{ xml: string; pdf?: Buffer }> {
538
556
  try {
539
557
  // Create a new invoice instance
540
- const einvoice = new plugins.einvoice.EInvoice();
558
+ const EInvoice = await this.getEInvoiceClass();
559
+ const einvoice: any = new EInvoice();
541
560
 
542
561
  // Set invoice data
543
562
  const businessTerms = this.mapToBusinessTerms(invoiceData);
@@ -558,7 +577,8 @@ export class InvoiceAdapter {
558
577
  return { xml, pdf };
559
578
  } catch (error) {
560
579
  this.logger.log('error', `Failed to generate invoice: ${error}`);
561
- throw new Error(`Invoice generation failed: ${error.message}`);
580
+ const errorMessage = error instanceof Error ? error.message : String(error);
581
+ throw new Error(`Invoice generation failed: ${errorMessage}`);
562
582
  }
563
583
  }
564
584
 
@@ -578,4 +598,4 @@ export class InvoiceAdapter {
578
598
  // This would be a comprehensive mapping in production
579
599
  };
580
600
  }
581
- }
601
+ }
@@ -131,10 +131,11 @@ export class InvoiceBookingEngine {
131
131
  };
132
132
  } catch (error) {
133
133
  this.logger.log('error', `Failed to book invoice: ${error}`);
134
+ const errorMessage = error instanceof Error ? error.message : String(error);
134
135
  return {
135
136
  success: false,
136
137
  confidence: 0,
137
- errors: [`Booking failed: ${error.message}`]
138
+ errors: [`Booking failed: ${errorMessage}`]
138
139
  };
139
140
  }
140
141
  }
@@ -574,10 +575,11 @@ export class InvoiceBookingEngine {
574
575
  };
575
576
  } catch (error) {
576
577
  this.logger.log('error', `Failed to book payment: ${error}`);
578
+ const errorMessage = error instanceof Error ? error.message : String(error);
577
579
  return {
578
580
  success: false,
579
581
  confidence: 0,
580
- errors: [`Payment booking failed: ${error.message}`]
582
+ errors: [`Payment booking failed: ${errorMessage}`]
581
583
  };
582
584
  }
583
585
  }
@@ -757,4 +759,4 @@ export class InvoiceBookingEngine {
757
759
 
758
760
  return Array.from(accounts);
759
761
  }
760
- }
762
+ }
@@ -224,7 +224,8 @@ export class InvoiceStorage {
224
224
  return contentHash;
225
225
  } catch (error) {
226
226
  this.logger.log('error', `Failed to store invoice: ${error}`);
227
- throw new Error(`Invoice storage failed: ${error.message}`);
227
+ const errorMessage = error instanceof Error ? error.message : String(error);
228
+ throw new Error(`Invoice storage failed: ${errorMessage}`);
228
229
  }
229
230
  }
230
231
 
@@ -707,4 +708,4 @@ export class InvoiceStorage {
707
708
 
708
709
  this.logger.log('info', `Updated metadata for invoice: ${contentHash}`);
709
710
  }
710
- }
711
+ }
@@ -2,6 +2,7 @@ import * as plugins from './plugins.js';
2
2
  import * as path from 'path';
3
3
  import * as crypto from 'crypto';
4
4
  import * as https from 'https';
5
+ import * as nodeForge from 'node-forge';
5
6
 
6
7
  export interface ISigningOptions {
7
8
  certificatePem?: string;
@@ -57,19 +58,19 @@ export class SecurityManager {
57
58
 
58
59
  try {
59
60
  // Parse certificate and key
60
- const certificate = plugins.nodeForge.pki.certificateFromPem(cert);
61
+ const certificate = nodeForge.pki.certificateFromPem(cert);
61
62
  const privateKey = this.options.privateKeyPassphrase
62
- ? plugins.nodeForge.pki.decryptRsaPrivateKey(key, this.options.privateKeyPassphrase)
63
- : plugins.nodeForge.pki.privateKeyFromPem(key);
63
+ ? nodeForge.pki.decryptRsaPrivateKey(key, this.options.privateKeyPassphrase)
64
+ : nodeForge.pki.privateKeyFromPem(key);
64
65
 
65
66
  // Create PKCS#7 signed data (CMS)
66
- const p7 = plugins.nodeForge.pkcs7.createSignedData();
67
+ const p7 = nodeForge.pkcs7.createSignedData();
67
68
 
68
69
  // Add content
69
70
  if (typeof data === 'string') {
70
- p7.content = plugins.nodeForge.util.createBuffer(data, 'utf8');
71
+ p7.content = nodeForge.util.createBuffer(data, 'utf8');
71
72
  } else {
72
- p7.content = plugins.nodeForge.util.createBuffer(data.toString('latin1'));
73
+ p7.content = nodeForge.util.createBuffer(data.toString('latin1'));
73
74
  }
74
75
 
75
76
  // Add certificate
@@ -79,17 +80,17 @@ export class SecurityManager {
79
80
  p7.addSigner({
80
81
  key: privateKey,
81
82
  certificate: certificate,
82
- digestAlgorithm: plugins.nodeForge.pki.oids.sha256,
83
+ digestAlgorithm: nodeForge.pki.oids.sha256,
83
84
  authenticatedAttributes: [
84
85
  {
85
- type: plugins.nodeForge.pki.oids.contentType,
86
- value: plugins.nodeForge.pki.oids.data
86
+ type: nodeForge.pki.oids.contentType,
87
+ value: nodeForge.pki.oids.data
87
88
  },
88
89
  {
89
- type: plugins.nodeForge.pki.oids.messageDigest
90
+ type: nodeForge.pki.oids.messageDigest
90
91
  },
91
92
  {
92
- type: plugins.nodeForge.pki.oids.signingTime,
93
+ type: nodeForge.pki.oids.signingTime,
93
94
  value: new Date().toISOString()
94
95
  }
95
96
  ]
@@ -99,7 +100,7 @@ export class SecurityManager {
99
100
  p7.sign({ detached: true });
100
101
 
101
102
  // Convert to PEM
102
- const pem = plugins.nodeForge.pkcs7.messageToPem(p7);
103
+ const pem = nodeForge.pkcs7.messageToPem(p7);
103
104
 
104
105
  // Extract base64 signature
105
106
  const signature = pem
@@ -237,14 +238,14 @@ export class SecurityManager {
237
238
  }
238
239
 
239
240
  // Parse the PKCS#7 message
240
- const p7 = plugins.nodeForge.pkcs7.messageFromPem(pemSignature);
241
+ const p7 = nodeForge.pkcs7.messageFromPem(pemSignature);
241
242
 
242
243
  // Prepare content for verification
243
- let content: plugins.nodeForge.util.ByteStringBuffer;
244
+ let content: nodeForge.util.ByteStringBuffer;
244
245
  if (typeof data === 'string') {
245
- content = plugins.nodeForge.util.createBuffer(data, 'utf8');
246
+ content = nodeForge.util.createBuffer(data, 'utf8');
246
247
  } else {
247
- content = plugins.nodeForge.util.createBuffer(data.toString('latin1'));
248
+ content = nodeForge.util.createBuffer(data.toString('latin1'));
248
249
  }
249
250
 
250
251
  // Verify the signature
@@ -267,8 +268,8 @@ export class SecurityManager {
267
268
  commonName: string = 'SKR Export System',
268
269
  validDays: number = 365
269
270
  ): Promise<{ certificate: string; privateKey: string }> {
270
- const keys = plugins.nodeForge.pki.rsa.generateKeyPair(2048);
271
- const cert = plugins.nodeForge.pki.createCertificate();
271
+ const keys = nodeForge.pki.rsa.generateKeyPair(2048);
272
+ const cert = nodeForge.pki.createCertificate();
272
273
 
273
274
  cert.publicKey = keys.publicKey;
274
275
  cert.serialNumber = '01';
@@ -326,11 +327,11 @@ export class SecurityManager {
326
327
  ]);
327
328
 
328
329
  // Self-sign certificate
329
- cert.sign(keys.privateKey, plugins.nodeForge.md.sha256.create());
330
+ cert.sign(keys.privateKey, nodeForge.md.sha256.create());
330
331
 
331
332
  // Convert to PEM
332
- const certificatePem = plugins.nodeForge.pki.certificateToPem(cert);
333
- const privateKeyPem = plugins.nodeForge.pki.privateKeyToPem(keys.privateKey);
333
+ const certificatePem = nodeForge.pki.certificateToPem(cert);
334
+ const privateKeyPem = nodeForge.pki.privateKeyToPem(keys.privateKey);
334
335
 
335
336
  return {
336
337
  certificate: certificatePem,
@@ -402,4 +403,4 @@ export class SecurityManager {
402
403
 
403
404
  return ltv;
404
405
  }
405
- }
406
+ }