@fast-white-cat/integration-ksef-direct 0.1.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/README.md +36 -0
- package/dist/index.js +2 -0
- package/dist/index.js.map +7 -0
- package/dist/modules/integration_ksef_direct/acl.js +13 -0
- package/dist/modules/integration_ksef_direct/acl.js.map +7 -0
- package/dist/modules/integration_ksef_direct/api/get/integration-ksef-direct/documents/[id].js +92 -0
- package/dist/modules/integration_ksef_direct/api/get/integration-ksef-direct/documents/[id].js.map +7 -0
- package/dist/modules/integration_ksef_direct/api/get/integration-ksef-direct/documents.js +105 -0
- package/dist/modules/integration_ksef_direct/api/get/integration-ksef-direct/documents.js.map +7 -0
- package/dist/modules/integration_ksef_direct/api/get/integration-ksef-direct/health.js +158 -0
- package/dist/modules/integration_ksef_direct/api/get/integration-ksef-direct/health.js.map +7 -0
- package/dist/modules/integration_ksef_direct/api/get/integration-ksef-direct/received-documents/[id].js +86 -0
- package/dist/modules/integration_ksef_direct/api/get/integration-ksef-direct/received-documents/[id].js.map +7 -0
- package/dist/modules/integration_ksef_direct/api/get/integration-ksef-direct/received-documents.js +112 -0
- package/dist/modules/integration_ksef_direct/api/get/integration-ksef-direct/received-documents.js.map +7 -0
- package/dist/modules/integration_ksef_direct/api/get/integration-ksef-direct/seller-info.js +54 -0
- package/dist/modules/integration_ksef_direct/api/get/integration-ksef-direct/seller-info.js.map +7 -0
- package/dist/modules/integration_ksef_direct/api/post/integration-ksef-direct/documents/[id]/send.js +64 -0
- package/dist/modules/integration_ksef_direct/api/post/integration-ksef-direct/documents/[id]/send.js.map +7 -0
- package/dist/modules/integration_ksef_direct/api/post/integration-ksef-direct/documents.js +104 -0
- package/dist/modules/integration_ksef_direct/api/post/integration-ksef-direct/documents.js.map +7 -0
- package/dist/modules/integration_ksef_direct/api/post/integration-ksef-direct/invoice-numbers.js +41 -0
- package/dist/modules/integration_ksef_direct/api/post/integration-ksef-direct/invoice-numbers.js.map +7 -0
- package/dist/modules/integration_ksef_direct/api/post/integration-ksef-direct/received-documents/fetch.js +172 -0
- package/dist/modules/integration_ksef_direct/api/post/integration-ksef-direct/received-documents/fetch.js.map +7 -0
- package/dist/modules/integration_ksef_direct/api/post/integration-ksef-direct/received-documents/sync.js +80 -0
- package/dist/modules/integration_ksef_direct/api/post/integration-ksef-direct/received-documents/sync.js.map +7 -0
- package/dist/modules/integration_ksef_direct/backend/integration-ksef-direct/documents/new/page.js +441 -0
- package/dist/modules/integration_ksef_direct/backend/integration-ksef-direct/documents/new/page.js.map +7 -0
- package/dist/modules/integration_ksef_direct/backend/integration-ksef-direct/documents/new/page.meta.js +8 -0
- package/dist/modules/integration_ksef_direct/backend/integration-ksef-direct/documents/new/page.meta.js.map +7 -0
- package/dist/modules/integration_ksef_direct/backend/integration-ksef-direct/documents/page.js +193 -0
- package/dist/modules/integration_ksef_direct/backend/integration-ksef-direct/documents/page.js.map +7 -0
- package/dist/modules/integration_ksef_direct/backend/integration-ksef-direct/received-documents/page.js +314 -0
- package/dist/modules/integration_ksef_direct/backend/integration-ksef-direct/received-documents/page.js.map +7 -0
- package/dist/modules/integration_ksef_direct/backend/page.js +154 -0
- package/dist/modules/integration_ksef_direct/backend/page.js.map +7 -0
- package/dist/modules/integration_ksef_direct/commands/create-ksef-direct-document.js +80 -0
- package/dist/modules/integration_ksef_direct/commands/create-ksef-direct-document.js.map +7 -0
- package/dist/modules/integration_ksef_direct/commands/enqueue-ksef-direct-document.js +43 -0
- package/dist/modules/integration_ksef_direct/commands/enqueue-ksef-direct-document.js.map +7 -0
- package/dist/modules/integration_ksef_direct/data/entities.js +224 -0
- package/dist/modules/integration_ksef_direct/data/entities.js.map +7 -0
- package/dist/modules/integration_ksef_direct/data/validators.js +103 -0
- package/dist/modules/integration_ksef_direct/data/validators.js.map +7 -0
- package/dist/modules/integration_ksef_direct/di.js +11 -0
- package/dist/modules/integration_ksef_direct/di.js.map +7 -0
- package/dist/modules/integration_ksef_direct/events.js +21 -0
- package/dist/modules/integration_ksef_direct/events.js.map +7 -0
- package/dist/modules/integration_ksef_direct/index.js +10 -0
- package/dist/modules/integration_ksef_direct/index.js.map +7 -0
- package/dist/modules/integration_ksef_direct/integration.js +56 -0
- package/dist/modules/integration_ksef_direct/integration.js.map +7 -0
- package/dist/modules/integration_ksef_direct/lib/health.js +32 -0
- package/dist/modules/integration_ksef_direct/lib/health.js.map +7 -0
- package/dist/modules/integration_ksef_direct/lib/invoiceNumberFormat.js +23 -0
- package/dist/modules/integration_ksef_direct/lib/invoiceNumberFormat.js.map +7 -0
- package/dist/modules/integration_ksef_direct/lib/ksefClient.js +523 -0
- package/dist/modules/integration_ksef_direct/lib/ksefClient.js.map +7 -0
- package/dist/modules/integration_ksef_direct/lib/ksefCrypto.js +103 -0
- package/dist/modules/integration_ksef_direct/lib/ksefCrypto.js.map +7 -0
- package/dist/modules/integration_ksef_direct/lib/ksefFa2Xml.js +123 -0
- package/dist/modules/integration_ksef_direct/lib/ksefFa2Xml.js.map +7 -0
- package/dist/modules/integration_ksef_direct/lib/ksefXmlParser.js +76 -0
- package/dist/modules/integration_ksef_direct/lib/ksefXmlParser.js.map +7 -0
- package/dist/modules/integration_ksef_direct/migrations/Migration20260519210000_integration_ksef_direct.js +15 -0
- package/dist/modules/integration_ksef_direct/migrations/Migration20260519210000_integration_ksef_direct.js.map +7 -0
- package/dist/modules/integration_ksef_direct/migrations/Migration20260520120000_ksef_direct_documents.js +17 -0
- package/dist/modules/integration_ksef_direct/migrations/Migration20260520120000_ksef_direct_documents.js.map +7 -0
- package/dist/modules/integration_ksef_direct/migrations/Migration20260520220000_ksef_direct_send_queue.js +15 -0
- package/dist/modules/integration_ksef_direct/migrations/Migration20260520220000_ksef_direct_send_queue.js.map +7 -0
- package/dist/modules/integration_ksef_direct/migrations/Migration20260520230000_ksef_direct_seller_per_document.js +17 -0
- package/dist/modules/integration_ksef_direct/migrations/Migration20260520230000_ksef_direct_seller_per_document.js.map +7 -0
- package/dist/modules/integration_ksef_direct/migrations/Migration20260521120000_ksef_direct_received_documents.js +16 -0
- package/dist/modules/integration_ksef_direct/migrations/Migration20260521120000_ksef_direct_received_documents.js.map +7 -0
- package/dist/modules/integration_ksef_direct/migrations/Migration20260521130000_ksef_received_download_urls.js +15 -0
- package/dist/modules/integration_ksef_direct/migrations/Migration20260521130000_ksef_received_download_urls.js.map +7 -0
- package/dist/modules/integration_ksef_direct/setup.js +11 -0
- package/dist/modules/integration_ksef_direct/setup.js.map +7 -0
- package/dist/modules/integration_ksef_direct/subscribers/auto-enqueue-ksef-document.js +19 -0
- package/dist/modules/integration_ksef_direct/subscribers/auto-enqueue-ksef-document.js.map +7 -0
- package/dist/modules/integration_ksef_direct/workers/check-ksef-document-status.js +103 -0
- package/dist/modules/integration_ksef_direct/workers/check-ksef-document-status.js.map +7 -0
- package/dist/modules/integration_ksef_direct/workers/send-ksef-document.js +104 -0
- package/dist/modules/integration_ksef_direct/workers/send-ksef-document.js.map +7 -0
- package/dist/modules/integration_ksef_direct/workers/sync-received-documents.js +137 -0
- package/dist/modules/integration_ksef_direct/workers/sync-received-documents.js.map +7 -0
- package/dist/types/declarations.d.js +1 -0
- package/dist/types/declarations.d.js.map +7 -0
- package/package.json +98 -0
- package/src/index.ts +1 -0
- package/src/modules/integration_ksef_direct/__tests__/invoiceNumberFormat.test.ts +42 -0
- package/src/modules/integration_ksef_direct/__tests__/ksefFa2Xml.test.ts +407 -0
- package/src/modules/integration_ksef_direct/__tests__/ksefXmlParser.test.ts +230 -0
- package/src/modules/integration_ksef_direct/acl.ts +9 -0
- package/src/modules/integration_ksef_direct/api/get/integration-ksef-direct/documents/[id].ts +94 -0
- package/src/modules/integration_ksef_direct/api/get/integration-ksef-direct/documents.ts +111 -0
- package/src/modules/integration_ksef_direct/api/get/integration-ksef-direct/health.ts +194 -0
- package/src/modules/integration_ksef_direct/api/get/integration-ksef-direct/received-documents/[id].ts +88 -0
- package/src/modules/integration_ksef_direct/api/get/integration-ksef-direct/received-documents.ts +119 -0
- package/src/modules/integration_ksef_direct/api/get/integration-ksef-direct/seller-info.ts +62 -0
- package/src/modules/integration_ksef_direct/api/post/integration-ksef-direct/documents/[id]/send.ts +64 -0
- package/src/modules/integration_ksef_direct/api/post/integration-ksef-direct/documents.ts +109 -0
- package/src/modules/integration_ksef_direct/api/post/integration-ksef-direct/invoice-numbers.ts +40 -0
- package/src/modules/integration_ksef_direct/api/post/integration-ksef-direct/received-documents/fetch.ts +185 -0
- package/src/modules/integration_ksef_direct/api/post/integration-ksef-direct/received-documents/sync.ts +86 -0
- package/src/modules/integration_ksef_direct/backend/integration-ksef-direct/documents/new/page.meta.ts +4 -0
- package/src/modules/integration_ksef_direct/backend/integration-ksef-direct/documents/new/page.tsx +470 -0
- package/src/modules/integration_ksef_direct/backend/integration-ksef-direct/documents/page.tsx +233 -0
- package/src/modules/integration_ksef_direct/backend/integration-ksef-direct/received-documents/page.tsx +415 -0
- package/src/modules/integration_ksef_direct/backend/page.tsx +183 -0
- package/src/modules/integration_ksef_direct/commands/create-ksef-direct-document.ts +93 -0
- package/src/modules/integration_ksef_direct/commands/enqueue-ksef-direct-document.ts +57 -0
- package/src/modules/integration_ksef_direct/data/entities.ts +195 -0
- package/src/modules/integration_ksef_direct/data/validators.ts +115 -0
- package/src/modules/integration_ksef_direct/di.ts +9 -0
- package/src/modules/integration_ksef_direct/events.ts +18 -0
- package/src/modules/integration_ksef_direct/i18n/en.json +115 -0
- package/src/modules/integration_ksef_direct/i18n/pl.json +115 -0
- package/src/modules/integration_ksef_direct/index.ts +6 -0
- package/src/modules/integration_ksef_direct/integration.ts +54 -0
- package/src/modules/integration_ksef_direct/lib/health.ts +43 -0
- package/src/modules/integration_ksef_direct/lib/invoiceNumberFormat.ts +23 -0
- package/src/modules/integration_ksef_direct/lib/ksefClient.ts +668 -0
- package/src/modules/integration_ksef_direct/lib/ksefCrypto.ts +138 -0
- package/src/modules/integration_ksef_direct/lib/ksefFa2Xml.ts +147 -0
- package/src/modules/integration_ksef_direct/lib/ksefXmlParser.ts +97 -0
- package/src/modules/integration_ksef_direct/migrations/.snapshot-open-mercato.json +1028 -0
- package/src/modules/integration_ksef_direct/migrations/Migration20260519210000_integration_ksef_direct.ts +15 -0
- package/src/modules/integration_ksef_direct/migrations/Migration20260520120000_ksef_direct_documents.ts +17 -0
- package/src/modules/integration_ksef_direct/migrations/Migration20260520220000_ksef_direct_send_queue.ts +15 -0
- package/src/modules/integration_ksef_direct/migrations/Migration20260520230000_ksef_direct_seller_per_document.ts +17 -0
- package/src/modules/integration_ksef_direct/migrations/Migration20260521120000_ksef_direct_received_documents.ts +16 -0
- package/src/modules/integration_ksef_direct/migrations/Migration20260521130000_ksef_received_download_urls.ts +15 -0
- package/src/modules/integration_ksef_direct/setup.ts +9 -0
- package/src/modules/integration_ksef_direct/subscribers/auto-enqueue-ksef-document.ts +21 -0
- package/src/modules/integration_ksef_direct/workers/check-ksef-document-status.ts +129 -0
- package/src/modules/integration_ksef_direct/workers/send-ksef-document.ts +137 -0
- package/src/modules/integration_ksef_direct/workers/sync-received-documents.ts +171 -0
- package/src/types/declarations.d.ts +1 -0
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import crypto from "node:crypto";
|
|
2
|
+
const BASE_URLS = {
|
|
3
|
+
test: "https://api-test.ksef.mf.gov.pl/v2",
|
|
4
|
+
production: "https://api.ksef.mf.gov.pl/v2"
|
|
5
|
+
};
|
|
6
|
+
const PUBLIC_KEY_CACHE = /* @__PURE__ */ new Map();
|
|
7
|
+
const CACHE_TTL_MS = 24 * 60 * 60 * 1e3;
|
|
8
|
+
async function fetchCertificates(environment) {
|
|
9
|
+
const url = `${BASE_URLS[environment]}/security/public-key-certificates`;
|
|
10
|
+
const response = await fetch(url, {
|
|
11
|
+
method: "GET",
|
|
12
|
+
headers: { "Accept": "application/json" },
|
|
13
|
+
signal: AbortSignal.timeout(1e4)
|
|
14
|
+
});
|
|
15
|
+
if (!response.ok) {
|
|
16
|
+
throw new Error(`Failed to fetch KSeF public key certificates: HTTP ${response.status}`);
|
|
17
|
+
}
|
|
18
|
+
const data = await response.json();
|
|
19
|
+
if (!Array.isArray(data)) {
|
|
20
|
+
throw new Error("KSeF public key response is not an array");
|
|
21
|
+
}
|
|
22
|
+
return data;
|
|
23
|
+
}
|
|
24
|
+
function certToPem(entry) {
|
|
25
|
+
const derBuffer = Buffer.from(entry.certificate, "base64");
|
|
26
|
+
const x509 = new crypto.X509Certificate(derBuffer);
|
|
27
|
+
return x509.publicKey.export({ type: "spki", format: "pem" }).toString();
|
|
28
|
+
}
|
|
29
|
+
async function fetchPublicKey(environment) {
|
|
30
|
+
const cached = PUBLIC_KEY_CACHE.get(environment);
|
|
31
|
+
if (cached && Date.now() - cached.fetchedAt < CACHE_TTL_MS) {
|
|
32
|
+
return cached.publicKeyPem;
|
|
33
|
+
}
|
|
34
|
+
const certs = await fetchCertificates(environment);
|
|
35
|
+
const tokenCert = certs.find((entry) => entry.usage?.includes("KsefTokenEncryption"));
|
|
36
|
+
if (!tokenCert?.certificate) {
|
|
37
|
+
throw new Error("KSeF public key response missing KsefTokenEncryption certificate");
|
|
38
|
+
}
|
|
39
|
+
const publicKeyPem = certToPem(tokenCert);
|
|
40
|
+
PUBLIC_KEY_CACHE.set(environment, { publicKeyPem, fetchedAt: Date.now() });
|
|
41
|
+
return publicKeyPem;
|
|
42
|
+
}
|
|
43
|
+
async function fetchInvoicePublicKey(environment) {
|
|
44
|
+
const certs = await fetchCertificates(environment);
|
|
45
|
+
const invoiceCert = certs.find((entry) => entry.usage?.includes("SymmetricKeyEncryption")) ?? certs.find((entry) => entry.usage?.includes("KsefTokenEncryption"));
|
|
46
|
+
if (!invoiceCert?.certificate) {
|
|
47
|
+
throw new Error("KSeF public key response missing invoice encryption certificate");
|
|
48
|
+
}
|
|
49
|
+
return { publicKeyPem: certToPem(invoiceCert), publicKeyId: invoiceCert.publicKeyId };
|
|
50
|
+
}
|
|
51
|
+
function clearPublicKeyCache(environment) {
|
|
52
|
+
if (environment) {
|
|
53
|
+
PUBLIC_KEY_CACHE.delete(environment);
|
|
54
|
+
} else {
|
|
55
|
+
PUBLIC_KEY_CACHE.clear();
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
function encryptKsefToken(token, timestampMs, publicKeyPem) {
|
|
59
|
+
const plaintext = `${token}|${timestampMs}`;
|
|
60
|
+
const encrypted = crypto.publicEncrypt(
|
|
61
|
+
{
|
|
62
|
+
key: publicKeyPem,
|
|
63
|
+
padding: crypto.constants.RSA_PKCS1_OAEP_PADDING,
|
|
64
|
+
oaepHash: "sha256"
|
|
65
|
+
},
|
|
66
|
+
Buffer.from(plaintext, "utf-8")
|
|
67
|
+
);
|
|
68
|
+
return encrypted.toString("base64");
|
|
69
|
+
}
|
|
70
|
+
function generateSymmetricKey() {
|
|
71
|
+
return {
|
|
72
|
+
key: crypto.randomBytes(32),
|
|
73
|
+
iv: crypto.randomBytes(16)
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
function prepareInvoicePayload(xmlString, publicKeyPem) {
|
|
77
|
+
const { key, iv } = generateSymmetricKey();
|
|
78
|
+
const xmlBytes = Buffer.from(xmlString, "utf-8");
|
|
79
|
+
const cipher = crypto.createCipheriv("aes-256-cbc", key, iv);
|
|
80
|
+
const encryptedContent = Buffer.concat([cipher.update(xmlBytes), cipher.final()]);
|
|
81
|
+
const encryptedSymmetricKey = crypto.publicEncrypt(
|
|
82
|
+
{ key: publicKeyPem, padding: crypto.constants.RSA_PKCS1_OAEP_PADDING, oaepHash: "sha256" },
|
|
83
|
+
key
|
|
84
|
+
);
|
|
85
|
+
return {
|
|
86
|
+
encryptedSymmetricKey: encryptedSymmetricKey.toString("base64"),
|
|
87
|
+
initializationVector: iv.toString("base64"),
|
|
88
|
+
encryptedInvoiceContent: encryptedContent.toString("base64"),
|
|
89
|
+
invoiceHash: crypto.createHash("sha256").update(xmlBytes).digest("base64"),
|
|
90
|
+
invoiceSize: xmlBytes.length,
|
|
91
|
+
encryptedInvoiceHash: crypto.createHash("sha256").update(encryptedContent).digest("base64"),
|
|
92
|
+
encryptedInvoiceSize: encryptedContent.length
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
export {
|
|
96
|
+
clearPublicKeyCache,
|
|
97
|
+
encryptKsefToken,
|
|
98
|
+
fetchInvoicePublicKey,
|
|
99
|
+
fetchPublicKey,
|
|
100
|
+
generateSymmetricKey,
|
|
101
|
+
prepareInvoicePayload
|
|
102
|
+
};
|
|
103
|
+
//# sourceMappingURL=ksefCrypto.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../src/modules/integration_ksef_direct/lib/ksefCrypto.ts"],
|
|
4
|
+
"sourcesContent": ["import crypto from 'node:crypto'\n\ntype KsefEnvironment = 'test' | 'production'\n\nconst BASE_URLS: Record<KsefEnvironment, string> = {\n test: 'https://api-test.ksef.mf.gov.pl/v2',\n production: 'https://api.ksef.mf.gov.pl/v2',\n}\n\ninterface PublicKeyCacheEntry {\n publicKeyPem: string\n fetchedAt: number\n}\n\nconst PUBLIC_KEY_CACHE = new Map<KsefEnvironment, PublicKeyCacheEntry>()\nconst CACHE_TTL_MS = 24 * 60 * 60 * 1000\n\ninterface PublicKeyCertificateEntry {\n certificate: string\n certificateId: string\n publicKeyId?: string\n validFrom?: string\n validTo?: string\n usage?: string[]\n}\n\nasync function fetchCertificates(environment: KsefEnvironment): Promise<PublicKeyCertificateEntry[]> {\n const url = `${BASE_URLS[environment]}/security/public-key-certificates`\n const response = await fetch(url, {\n method: 'GET',\n headers: { 'Accept': 'application/json' },\n signal: AbortSignal.timeout(10_000),\n })\n if (!response.ok) {\n throw new Error(`Failed to fetch KSeF public key certificates: HTTP ${response.status}`)\n }\n const data = await response.json() as PublicKeyCertificateEntry[]\n if (!Array.isArray(data)) {\n throw new Error('KSeF public key response is not an array')\n }\n return data\n}\n\nfunction certToPem(entry: PublicKeyCertificateEntry): string {\n const derBuffer = Buffer.from(entry.certificate, 'base64')\n const x509 = new crypto.X509Certificate(derBuffer)\n return x509.publicKey.export({ type: 'spki', format: 'pem' }).toString()\n}\n\nexport async function fetchPublicKey(environment: KsefEnvironment): Promise<string> {\n const cached = PUBLIC_KEY_CACHE.get(environment)\n if (cached && Date.now() - cached.fetchedAt < CACHE_TTL_MS) {\n return cached.publicKeyPem\n }\n\n const certs = await fetchCertificates(environment)\n const tokenCert = certs.find(entry => entry.usage?.includes('KsefTokenEncryption'))\n if (!tokenCert?.certificate) {\n throw new Error('KSeF public key response missing KsefTokenEncryption certificate')\n }\n const publicKeyPem = certToPem(tokenCert)\n PUBLIC_KEY_CACHE.set(environment, { publicKeyPem, fetchedAt: Date.now() })\n return publicKeyPem\n}\n\nexport async function fetchInvoicePublicKey(\n environment: KsefEnvironment,\n): Promise<{ publicKeyPem: string; publicKeyId?: string }> {\n const certs = await fetchCertificates(environment)\n const invoiceCert = certs.find(entry => entry.usage?.includes('SymmetricKeyEncryption'))\n ?? certs.find(entry => entry.usage?.includes('KsefTokenEncryption'))\n if (!invoiceCert?.certificate) {\n throw new Error('KSeF public key response missing invoice encryption certificate')\n }\n return { publicKeyPem: certToPem(invoiceCert), publicKeyId: invoiceCert.publicKeyId }\n}\n\nexport function clearPublicKeyCache(environment?: KsefEnvironment): void {\n if (environment) {\n PUBLIC_KEY_CACHE.delete(environment)\n } else {\n PUBLIC_KEY_CACHE.clear()\n }\n}\n\nexport function encryptKsefToken(token: string, timestampMs: number, publicKeyPem: string): string {\n const plaintext = `${token}|${timestampMs}`\n const encrypted = crypto.publicEncrypt(\n {\n key: publicKeyPem,\n padding: crypto.constants.RSA_PKCS1_OAEP_PADDING,\n oaepHash: 'sha256',\n },\n Buffer.from(plaintext, 'utf-8'),\n )\n return encrypted.toString('base64')\n}\n\nexport function generateSymmetricKey(): { key: Buffer; iv: Buffer } {\n return {\n key: crypto.randomBytes(32),\n iv: crypto.randomBytes(16),\n }\n}\n\nexport function prepareInvoicePayload(\n xmlString: string,\n publicKeyPem: string,\n): {\n encryptedSymmetricKey: string\n initializationVector: string\n encryptedInvoiceContent: string\n invoiceHash: string\n invoiceSize: number\n encryptedInvoiceHash: string\n encryptedInvoiceSize: number\n} {\n const { key, iv } = generateSymmetricKey()\n const xmlBytes = Buffer.from(xmlString, 'utf-8')\n\n const cipher = crypto.createCipheriv('aes-256-cbc', key, iv)\n const encryptedContent = Buffer.concat([cipher.update(xmlBytes), cipher.final()])\n\n const encryptedSymmetricKey = crypto.publicEncrypt(\n { key: publicKeyPem, padding: crypto.constants.RSA_PKCS1_OAEP_PADDING, oaepHash: 'sha256' },\n key,\n )\n\n return {\n encryptedSymmetricKey: encryptedSymmetricKey.toString('base64'),\n initializationVector: iv.toString('base64'),\n encryptedInvoiceContent: encryptedContent.toString('base64'),\n invoiceHash: crypto.createHash('sha256').update(xmlBytes).digest('base64'),\n invoiceSize: xmlBytes.length,\n encryptedInvoiceHash: crypto.createHash('sha256').update(encryptedContent).digest('base64'),\n encryptedInvoiceSize: encryptedContent.length,\n }\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
class KsefXmlGenerationError extends Error {
|
|
2
|
+
constructor(message) {
|
|
3
|
+
super(message);
|
|
4
|
+
this.name = "KsefXmlGenerationError";
|
|
5
|
+
}
|
|
6
|
+
}
|
|
7
|
+
function escapeXml(str) {
|
|
8
|
+
return str.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
9
|
+
}
|
|
10
|
+
function formatDate(date) {
|
|
11
|
+
return date.toISOString().split("T")[0];
|
|
12
|
+
}
|
|
13
|
+
const VAT_RATE_GROUPS = {
|
|
14
|
+
"23": { suffix: "1", p12Code: "23", hasVat: true },
|
|
15
|
+
"8": { suffix: "2", p12Code: "8", hasVat: true },
|
|
16
|
+
"5": { suffix: "3", p12Code: "5", hasVat: true },
|
|
17
|
+
"0": { suffix: "4", p12Code: "0", hasVat: false },
|
|
18
|
+
"ZW": { suffix: "5", p12Code: "zw", hasVat: false },
|
|
19
|
+
"NP": { suffix: "6", p12Code: "np", hasVat: false }
|
|
20
|
+
};
|
|
21
|
+
function generateFa2Xml(document, seller) {
|
|
22
|
+
if (!seller.sellerName.trim()) {
|
|
23
|
+
throw new KsefXmlGenerationError("sellerName is required for FA_VAT 2.0 XML generation");
|
|
24
|
+
}
|
|
25
|
+
if (!seller.sellerAddressL1?.trim()) {
|
|
26
|
+
throw new KsefXmlGenerationError("sellerAddressL1 is required for FA_VAT 2.0 XML generation");
|
|
27
|
+
}
|
|
28
|
+
const now = /* @__PURE__ */ new Date();
|
|
29
|
+
const issueDate = formatDate(document.issueDate);
|
|
30
|
+
const saleDate = document.saleDate ? formatDate(document.saleDate) : issueDate;
|
|
31
|
+
const lineItemsXml = document.lineItems.map((item, index) => {
|
|
32
|
+
const group = VAT_RATE_GROUPS[item.vatRate];
|
|
33
|
+
const p12 = group?.p12Code ?? item.vatRate;
|
|
34
|
+
return `
|
|
35
|
+
<FaWiersz>
|
|
36
|
+
<NrWierszaFa>${index + 1}</NrWierszaFa>
|
|
37
|
+
<P_7>${escapeXml(item.description)}</P_7>
|
|
38
|
+
<P_8A>${escapeXml(item.unit)}</P_8A>
|
|
39
|
+
<P_8B>${item.quantity}</P_8B>
|
|
40
|
+
<P_9A>${item.unitNetPrice.toFixed(2)}</P_9A>
|
|
41
|
+
<P_11>${item.netAmount.toFixed(2)}</P_11>
|
|
42
|
+
<P_12>${escapeXml(p12)}</P_12>
|
|
43
|
+
</FaWiersz>`;
|
|
44
|
+
}).join("");
|
|
45
|
+
const groups = /* @__PURE__ */ new Map();
|
|
46
|
+
for (const item of document.lineItems) {
|
|
47
|
+
const group = VAT_RATE_GROUPS[item.vatRate];
|
|
48
|
+
if (!group) continue;
|
|
49
|
+
const existing = groups.get(group.suffix) ?? { net: 0, vat: 0, hasVat: group.hasVat };
|
|
50
|
+
groups.set(group.suffix, {
|
|
51
|
+
net: existing.net + item.netAmount,
|
|
52
|
+
vat: existing.vat + item.vatAmount,
|
|
53
|
+
hasVat: group.hasVat
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
const sortedSuffixes = [...groups.keys()].sort();
|
|
57
|
+
const vatSummaryXml = sortedSuffixes.map((suffix) => {
|
|
58
|
+
const g = groups.get(suffix);
|
|
59
|
+
const net = `
|
|
60
|
+
<P_13_${suffix}>${g.net.toFixed(2)}</P_13_${suffix}>`;
|
|
61
|
+
const vat = g.hasVat ? `
|
|
62
|
+
<P_14_${suffix}>${g.vat.toFixed(2)}</P_14_${suffix}>` : "";
|
|
63
|
+
return net + vat;
|
|
64
|
+
}).join("");
|
|
65
|
+
const adresL2 = seller.sellerCity?.trim() ? `
|
|
66
|
+
<AdresL2>${escapeXml(seller.sellerCity)}</AdresL2>` : "";
|
|
67
|
+
const adresXml = `
|
|
68
|
+
<Adres>
|
|
69
|
+
<KodKraju>${escapeXml(seller.sellerCountry ?? "PL")}</KodKraju>
|
|
70
|
+
<AdresL1>${escapeXml(seller.sellerAddressL1)}</AdresL1>${adresL2}
|
|
71
|
+
</Adres>`;
|
|
72
|
+
const grossAmount = parseFloat(String(document.grossAmount)).toFixed(2);
|
|
73
|
+
return `<?xml version="1.0" encoding="UTF-8"?>
|
|
74
|
+
<Faktura xmlns="http://crd.gov.pl/wzor/2023/06/29/12648/">
|
|
75
|
+
<Naglowek>
|
|
76
|
+
<KodFormularza kodSystemowy="FA (2)" wersjaSchemy="1-0E">FA</KodFormularza>
|
|
77
|
+
<WariantFormularza>2</WariantFormularza>
|
|
78
|
+
<DataWytworzeniaFa>${now.toISOString()}</DataWytworzeniaFa>
|
|
79
|
+
<SystemInfo>OpenMercato</SystemInfo>
|
|
80
|
+
</Naglowek>
|
|
81
|
+
<Podmiot1>
|
|
82
|
+
<DaneIdentyfikacyjne>
|
|
83
|
+
<NIP>${escapeXml(document.sellerNip)}</NIP>
|
|
84
|
+
<Nazwa>${escapeXml(seller.sellerName)}</Nazwa>
|
|
85
|
+
</DaneIdentyfikacyjne>${adresXml}
|
|
86
|
+
</Podmiot1>
|
|
87
|
+
<Podmiot2>
|
|
88
|
+
<DaneIdentyfikacyjne>
|
|
89
|
+
<NIP>${escapeXml(document.buyerNip)}</NIP>
|
|
90
|
+
<Nazwa>${escapeXml(document.buyerName ?? "")}</Nazwa>
|
|
91
|
+
</DaneIdentyfikacyjne>
|
|
92
|
+
</Podmiot2>
|
|
93
|
+
<Fa>
|
|
94
|
+
<KodWaluty>${escapeXml(document.currency)}</KodWaluty>
|
|
95
|
+
<P_1>${issueDate}</P_1>
|
|
96
|
+
<P_2>${escapeXml(document.invoiceNumber)}</P_2>
|
|
97
|
+
<P_6>${saleDate}</P_6>${vatSummaryXml}
|
|
98
|
+
<P_15>${grossAmount}</P_15>
|
|
99
|
+
<Adnotacje>
|
|
100
|
+
<P_16>2</P_16>
|
|
101
|
+
<P_17>2</P_17>
|
|
102
|
+
<P_18>2</P_18>
|
|
103
|
+
<P_18A>2</P_18A>
|
|
104
|
+
<Zwolnienie>
|
|
105
|
+
<P_19N>1</P_19N>
|
|
106
|
+
</Zwolnienie>
|
|
107
|
+
<NoweSrodkiTransportu>
|
|
108
|
+
<P_22N>1</P_22N>
|
|
109
|
+
</NoweSrodkiTransportu>
|
|
110
|
+
<P_23>2</P_23>
|
|
111
|
+
<PMarzy>
|
|
112
|
+
<P_PMarzyN>1</P_PMarzyN>
|
|
113
|
+
</PMarzy>
|
|
114
|
+
</Adnotacje>
|
|
115
|
+
<RodzajFaktury>VAT</RodzajFaktury>${lineItemsXml}
|
|
116
|
+
</Fa>
|
|
117
|
+
</Faktura>`;
|
|
118
|
+
}
|
|
119
|
+
export {
|
|
120
|
+
KsefXmlGenerationError,
|
|
121
|
+
generateFa2Xml
|
|
122
|
+
};
|
|
123
|
+
//# sourceMappingURL=ksefFa2Xml.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../src/modules/integration_ksef_direct/lib/ksefFa2Xml.ts"],
|
|
4
|
+
"sourcesContent": ["import type { KsefDirectDocument } from '../data/entities'\n\nexport class KsefXmlGenerationError extends Error {\n constructor(message: string) {\n super(message)\n this.name = 'KsefXmlGenerationError'\n }\n}\n\nexport type SellerInfo = {\n sellerName: string\n sellerAddressL1?: string\n sellerCity?: string\n sellerCountry?: string\n}\n\nfunction escapeXml(str: string): string {\n return str\n .replace(/&/g, '&')\n .replace(/</g, '<')\n .replace(/>/g, '>')\n .replace(/\"/g, '"')\n .replace(/'/g, ''')\n}\n\nfunction formatDate(date: Date): string {\n return date.toISOString().split('T')[0]!\n}\n\n// vatRate \u2192 { suffix for P_13/P_14, p12Code for FaWiersz.P_12, whether VAT amount applies }\nconst VAT_RATE_GROUPS: Record<string, { suffix: string; p12Code: string; hasVat: boolean }> = {\n '23': { suffix: '1', p12Code: '23', hasVat: true },\n '8': { suffix: '2', p12Code: '8', hasVat: true },\n '5': { suffix: '3', p12Code: '5', hasVat: true },\n '0': { suffix: '4', p12Code: '0', hasVat: false },\n 'ZW': { suffix: '5', p12Code: 'zw', hasVat: false },\n 'NP': { suffix: '6', p12Code: 'np', hasVat: false },\n}\n\nexport function generateFa2Xml(document: KsefDirectDocument, seller: SellerInfo): string {\n if (!seller.sellerName.trim()) {\n throw new KsefXmlGenerationError('sellerName is required for FA_VAT 2.0 XML generation')\n }\n if (!seller.sellerAddressL1?.trim()) {\n throw new KsefXmlGenerationError('sellerAddressL1 is required for FA_VAT 2.0 XML generation')\n }\n\n const now = new Date()\n const issueDate = formatDate(document.issueDate)\n const saleDate = document.saleDate ? formatDate(document.saleDate) : issueDate\n\n const lineItemsXml = document.lineItems.map((item, index) => {\n const group = VAT_RATE_GROUPS[item.vatRate]\n const p12 = group?.p12Code ?? item.vatRate\n return `\n <FaWiersz>\n <NrWierszaFa>${index + 1}</NrWierszaFa>\n <P_7>${escapeXml(item.description)}</P_7>\n <P_8A>${escapeXml(item.unit)}</P_8A>\n <P_8B>${item.quantity}</P_8B>\n <P_9A>${item.unitNetPrice.toFixed(2)}</P_9A>\n <P_11>${item.netAmount.toFixed(2)}</P_11>\n <P_12>${escapeXml(p12)}</P_12>\n </FaWiersz>`\n }).join('')\n\n // Group by VAT rate, accumulate net + vat amounts\n const groups = new Map<string, { net: number; vat: number; hasVat: boolean }>()\n for (const item of document.lineItems) {\n const group = VAT_RATE_GROUPS[item.vatRate]\n if (!group) continue\n const existing = groups.get(group.suffix) ?? { net: 0, vat: 0, hasVat: group.hasVat }\n groups.set(group.suffix, {\n net: existing.net + item.netAmount,\n vat: existing.vat + item.vatAmount,\n hasVat: group.hasVat,\n })\n }\n\n // Sort suffix numerically for deterministic output\n const sortedSuffixes = [...groups.keys()].sort()\n const vatSummaryXml = sortedSuffixes.map((suffix) => {\n const g = groups.get(suffix)!\n const net = `\\n <P_13_${suffix}>${g.net.toFixed(2)}</P_13_${suffix}>`\n const vat = g.hasVat ? `\\n <P_14_${suffix}>${g.vat.toFixed(2)}</P_14_${suffix}>` : ''\n return net + vat\n }).join('')\n\n // TAdres: KodKraju \u2192 AdresL1 \u2192 [AdresL2] \u2014 city goes in AdresL2, no Miejscowosc element\n const adresL2 = seller.sellerCity?.trim()\n ? `\\n <AdresL2>${escapeXml(seller.sellerCity)}</AdresL2>`\n : ''\n const adresXml = `\n <Adres>\n <KodKraju>${escapeXml(seller.sellerCountry ?? 'PL')}</KodKraju>\n <AdresL1>${escapeXml(seller.sellerAddressL1)}</AdresL1>${adresL2}\n </Adres>`\n\n const grossAmount = parseFloat(String(document.grossAmount)).toFixed(2)\n\n // FA(2) v1-0E Fa sequence: KodWaluty \u2192 P_1 \u2192 P_2A \u2192 P_6 \u2192 VAT summaries \u2192 P_15 \u2192 Adnotacje \u2192 RodzajFaktury \u2192 FaWiersz\n return `<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Faktura xmlns=\"http://crd.gov.pl/wzor/2023/06/29/12648/\">\n <Naglowek>\n <KodFormularza kodSystemowy=\"FA (2)\" wersjaSchemy=\"1-0E\">FA</KodFormularza>\n <WariantFormularza>2</WariantFormularza>\n <DataWytworzeniaFa>${now.toISOString()}</DataWytworzeniaFa>\n <SystemInfo>OpenMercato</SystemInfo>\n </Naglowek>\n <Podmiot1>\n <DaneIdentyfikacyjne>\n <NIP>${escapeXml(document.sellerNip)}</NIP>\n <Nazwa>${escapeXml(seller.sellerName)}</Nazwa>\n </DaneIdentyfikacyjne>${adresXml}\n </Podmiot1>\n <Podmiot2>\n <DaneIdentyfikacyjne>\n <NIP>${escapeXml(document.buyerNip)}</NIP>\n <Nazwa>${escapeXml(document.buyerName ?? '')}</Nazwa>\n </DaneIdentyfikacyjne>\n </Podmiot2>\n <Fa>\n <KodWaluty>${escapeXml(document.currency)}</KodWaluty>\n <P_1>${issueDate}</P_1>\n <P_2>${escapeXml(document.invoiceNumber)}</P_2>\n <P_6>${saleDate}</P_6>${vatSummaryXml}\n <P_15>${grossAmount}</P_15>\n <Adnotacje>\n <P_16>2</P_16>\n <P_17>2</P_17>\n <P_18>2</P_18>\n <P_18A>2</P_18A>\n <Zwolnienie>\n <P_19N>1</P_19N>\n </Zwolnienie>\n <NoweSrodkiTransportu>\n <P_22N>1</P_22N>\n </NoweSrodkiTransportu>\n <P_23>2</P_23>\n <PMarzy>\n <P_PMarzyN>1</P_PMarzyN>\n </PMarzy>\n </Adnotacje>\n <RodzajFaktury>VAT</RodzajFaktury>${lineItemsXml}\n </Fa>\n</Faktura>`\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
function extractSection(xml, tag) {
|
|
2
|
+
const match = xml.match(new RegExp(`<${tag}[\\s\\S]*?>([\\s\\S]*?)<\\/${tag}>`, "i"));
|
|
3
|
+
return match ? match[1] : null;
|
|
4
|
+
}
|
|
5
|
+
function extractTag(xml, tag) {
|
|
6
|
+
const match = xml.match(new RegExp(`<${tag}[^>]*>([^<]*)<\\/${tag}>`, "i"));
|
|
7
|
+
return match ? match[1].trim() || null : null;
|
|
8
|
+
}
|
|
9
|
+
function sumTagPattern(xml, tagPattern) {
|
|
10
|
+
let sum = 0;
|
|
11
|
+
for (const match of xml.matchAll(new RegExp(`<(${tagPattern.source})>([^<]*)<\\/\\1>`, "gi"))) {
|
|
12
|
+
sum += parseFloat(match[2] ?? "0") || 0;
|
|
13
|
+
}
|
|
14
|
+
return sum;
|
|
15
|
+
}
|
|
16
|
+
function parseFa2Xml(xml) {
|
|
17
|
+
const podmiot1 = extractSection(xml, "Podmiot1");
|
|
18
|
+
const sellerNip = podmiot1 ? extractTag(podmiot1, "NIP") : null;
|
|
19
|
+
const sellerName = podmiot1 ? extractTag(podmiot1, "PelnaNazwa") ?? extractTag(podmiot1, "Nazwa") : null;
|
|
20
|
+
const fa = extractSection(xml, "Fa");
|
|
21
|
+
const issueDate = fa ? extractTag(fa, "P_1") : null;
|
|
22
|
+
const invoiceNumber = fa ? extractTag(fa, "P_2A") ?? extractTag(fa, "P_2") : null;
|
|
23
|
+
const currency = fa ? extractTag(fa, "KodWaluty") : null;
|
|
24
|
+
const grossAmountRaw = fa ? extractTag(fa, "P_15") : null;
|
|
25
|
+
const netAmountNum = fa ? sumTagPattern(fa, /P_13_\d+/) : 0;
|
|
26
|
+
const vatAmountNum = fa ? sumTagPattern(fa, /P_14_\d+/) : 0;
|
|
27
|
+
return {
|
|
28
|
+
invoiceNumber,
|
|
29
|
+
sellerNip,
|
|
30
|
+
sellerName,
|
|
31
|
+
issueDate,
|
|
32
|
+
currency,
|
|
33
|
+
netAmount: netAmountNum > 0 ? netAmountNum.toFixed(2) : null,
|
|
34
|
+
vatAmount: vatAmountNum > 0 ? vatAmountNum.toFixed(2) : null,
|
|
35
|
+
grossAmount: grossAmountRaw
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
function parseUpoXml(xml) {
|
|
39
|
+
const dokument = extractSection(xml, "Dokument");
|
|
40
|
+
const sellerNip = dokument ? extractTag(dokument, "NipSprzedawcy") : null;
|
|
41
|
+
const invoiceNumber = dokument ? extractTag(dokument, "NumerFaktury") : null;
|
|
42
|
+
const issueDate = dokument ? extractTag(dokument, "DataWystawieniaFaktury") : null;
|
|
43
|
+
return {
|
|
44
|
+
invoiceNumber,
|
|
45
|
+
sellerNip,
|
|
46
|
+
sellerName: null,
|
|
47
|
+
issueDate,
|
|
48
|
+
currency: null,
|
|
49
|
+
netAmount: null,
|
|
50
|
+
vatAmount: null,
|
|
51
|
+
grossAmount: null
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
function parseReceivedInvoiceXml(xml) {
|
|
55
|
+
try {
|
|
56
|
+
if (xml.includes("upo.schematy.mf.gov.pl") || xml.includes("<Potwierdzenie")) {
|
|
57
|
+
return parseUpoXml(xml);
|
|
58
|
+
}
|
|
59
|
+
return parseFa2Xml(xml);
|
|
60
|
+
} catch {
|
|
61
|
+
return {
|
|
62
|
+
invoiceNumber: null,
|
|
63
|
+
sellerNip: null,
|
|
64
|
+
sellerName: null,
|
|
65
|
+
issueDate: null,
|
|
66
|
+
currency: null,
|
|
67
|
+
netAmount: null,
|
|
68
|
+
vatAmount: null,
|
|
69
|
+
grossAmount: null
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
export {
|
|
74
|
+
parseReceivedInvoiceXml
|
|
75
|
+
};
|
|
76
|
+
//# sourceMappingURL=ksefXmlParser.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../src/modules/integration_ksef_direct/lib/ksefXmlParser.ts"],
|
|
4
|
+
"sourcesContent": ["export interface ParsedReceivedInvoice {\n invoiceNumber: string | null\n sellerNip: string | null\n sellerName: string | null\n issueDate: string | null\n currency: string | null\n netAmount: string | null\n vatAmount: string | null\n grossAmount: string | null\n}\n\nfunction extractSection(xml: string, tag: string): string | null {\n const match = xml.match(new RegExp(`<${tag}[\\\\s\\\\S]*?>([\\\\s\\\\S]*?)<\\\\/${tag}>`, 'i'))\n return match ? match[1]! : null\n}\n\nfunction extractTag(xml: string, tag: string): string | null {\n const match = xml.match(new RegExp(`<${tag}[^>]*>([^<]*)<\\\\/${tag}>`, 'i'))\n return match ? match[1]!.trim() || null : null\n}\n\nfunction sumTagPattern(xml: string, tagPattern: RegExp): number {\n let sum = 0\n for (const match of xml.matchAll(new RegExp(`<(${tagPattern.source})>([^<]*)<\\\\/\\\\1>`, 'gi'))) {\n sum += parseFloat(match[2] ?? '0') || 0\n }\n return sum\n}\n\nfunction parseFa2Xml(xml: string): ParsedReceivedInvoice {\n const podmiot1 = extractSection(xml, 'Podmiot1')\n const sellerNip = podmiot1 ? extractTag(podmiot1, 'NIP') : null\n const sellerName = podmiot1\n ? (extractTag(podmiot1, 'PelnaNazwa') ?? extractTag(podmiot1, 'Nazwa'))\n : null\n\n const fa = extractSection(xml, 'Fa')\n const issueDate = fa ? extractTag(fa, 'P_1') : null\n const invoiceNumber = fa ? (extractTag(fa, 'P_2A') ?? extractTag(fa, 'P_2')) : null\n const currency = fa ? extractTag(fa, 'KodWaluty') : null\n const grossAmountRaw = fa ? extractTag(fa, 'P_15') : null\n\n const netAmountNum = fa ? sumTagPattern(fa, /P_13_\\d+/) : 0\n const vatAmountNum = fa ? sumTagPattern(fa, /P_14_\\d+/) : 0\n\n return {\n invoiceNumber,\n sellerNip,\n sellerName,\n issueDate,\n currency,\n netAmount: netAmountNum > 0 ? netAmountNum.toFixed(2) : null,\n vatAmount: vatAmountNum > 0 ? vatAmountNum.toFixed(2) : null,\n grossAmount: grossAmountRaw,\n }\n}\n\nfunction parseUpoXml(xml: string): ParsedReceivedInvoice {\n // UPO (Potwierdzenie) format from KSeF \u2014 xmlns=\"http://upo.schematy.mf.gov.pl/KSeF/...\"\n // Contains metadata about an accepted invoice but not full financial data.\n const dokument = extractSection(xml, 'Dokument')\n const sellerNip = dokument ? extractTag(dokument, 'NipSprzedawcy') : null\n const invoiceNumber = dokument ? extractTag(dokument, 'NumerFaktury') : null\n const issueDate = dokument ? extractTag(dokument, 'DataWystawieniaFaktury') : null\n\n return {\n invoiceNumber,\n sellerNip,\n sellerName: null,\n issueDate,\n currency: null,\n netAmount: null,\n vatAmount: null,\n grossAmount: null,\n }\n}\n\nexport function parseReceivedInvoiceXml(xml: string): ParsedReceivedInvoice {\n try {\n // Detect UPO format by namespace\n if (xml.includes('upo.schematy.mf.gov.pl') || xml.includes('<Potwierdzenie')) {\n return parseUpoXml(xml)\n }\n return parseFa2Xml(xml)\n } catch {\n return {\n invoiceNumber: null,\n sellerNip: null,\n sellerName: null,\n issueDate: null,\n currency: null,\n netAmount: null,\n vatAmount: null,\n grossAmount: null,\n }\n }\n}\n"],
|
|
5
|
+
"mappings": "AAWA,SAAS,eAAe,KAAa,KAA4B;AAC/D,QAAM,QAAQ,IAAI,MAAM,IAAI,OAAO,IAAI,GAAG,8BAA8B,GAAG,KAAK,GAAG,CAAC;AACpF,SAAO,QAAQ,MAAM,CAAC,IAAK;AAC7B;AAEA,SAAS,WAAW,KAAa,KAA4B;AAC3D,QAAM,QAAQ,IAAI,MAAM,IAAI,OAAO,IAAI,GAAG,oBAAoB,GAAG,KAAK,GAAG,CAAC;AAC1E,SAAO,QAAQ,MAAM,CAAC,EAAG,KAAK,KAAK,OAAO;AAC5C;AAEA,SAAS,cAAc,KAAa,YAA4B;AAC9D,MAAI,MAAM;AACV,aAAW,SAAS,IAAI,SAAS,IAAI,OAAO,KAAK,WAAW,MAAM,qBAAqB,IAAI,CAAC,GAAG;AAC7F,WAAO,WAAW,MAAM,CAAC,KAAK,GAAG,KAAK;AAAA,EACxC;AACA,SAAO;AACT;AAEA,SAAS,YAAY,KAAoC;AACvD,QAAM,WAAW,eAAe,KAAK,UAAU;AAC/C,QAAM,YAAY,WAAW,WAAW,UAAU,KAAK,IAAI;AAC3D,QAAM,aAAa,WACd,WAAW,UAAU,YAAY,KAAK,WAAW,UAAU,OAAO,IACnE;AAEJ,QAAM,KAAK,eAAe,KAAK,IAAI;AACnC,QAAM,YAAY,KAAK,WAAW,IAAI,KAAK,IAAI;AAC/C,QAAM,gBAAgB,KAAM,WAAW,IAAI,MAAM,KAAK,WAAW,IAAI,KAAK,IAAK;AAC/E,QAAM,WAAW,KAAK,WAAW,IAAI,WAAW,IAAI;AACpD,QAAM,iBAAiB,KAAK,WAAW,IAAI,MAAM,IAAI;AAErD,QAAM,eAAe,KAAK,cAAc,IAAI,UAAU,IAAI;AAC1D,QAAM,eAAe,KAAK,cAAc,IAAI,UAAU,IAAI;AAE1D,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,WAAW,eAAe,IAAI,aAAa,QAAQ,CAAC,IAAI;AAAA,IACxD,WAAW,eAAe,IAAI,aAAa,QAAQ,CAAC,IAAI;AAAA,IACxD,aAAa;AAAA,EACf;AACF;AAEA,SAAS,YAAY,KAAoC;AAGvD,QAAM,WAAW,eAAe,KAAK,UAAU;AAC/C,QAAM,YAAY,WAAW,WAAW,UAAU,eAAe,IAAI;AACrE,QAAM,gBAAgB,WAAW,WAAW,UAAU,cAAc,IAAI;AACxE,QAAM,YAAY,WAAW,WAAW,UAAU,wBAAwB,IAAI;AAE9E,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,YAAY;AAAA,IACZ;AAAA,IACA,UAAU;AAAA,IACV,WAAW;AAAA,IACX,WAAW;AAAA,IACX,aAAa;AAAA,EACf;AACF;AAEO,SAAS,wBAAwB,KAAoC;AAC1E,MAAI;AAEF,QAAI,IAAI,SAAS,wBAAwB,KAAK,IAAI,SAAS,gBAAgB,GAAG;AAC5E,aAAO,YAAY,GAAG;AAAA,IACxB;AACA,WAAO,YAAY,GAAG;AAAA,EACxB,QAAQ;AACN,WAAO;AAAA,MACL,eAAe;AAAA,MACf,WAAW;AAAA,MACX,YAAY;AAAA,MACZ,WAAW;AAAA,MACX,UAAU;AAAA,MACV,WAAW;AAAA,MACX,WAAW;AAAA,MACX,aAAa;AAAA,IACf;AAAA,EACF;AACF;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { Migration } from "@mikro-orm/migrations";
|
|
2
|
+
class Migration20260519210000_integration_ksef_direct extends Migration {
|
|
3
|
+
up() {
|
|
4
|
+
this.addSql(`create table "ksef_direct_connections" ("id" uuid not null default gen_random_uuid(), "organization_id" uuid not null, "tenant_id" uuid not null, "status" text not null default 'unconfigured', "last_checked_at" timestamptz null, "error_message" text null, "error_code" text null, "created_at" timestamptz not null, "updated_at" timestamptz not null, primary key ("id"));`);
|
|
5
|
+
this.addSql(`create index "ksef_direct_connections_status_updated_at_index" on "ksef_direct_connections" ("status", "updated_at");`);
|
|
6
|
+
this.addSql(`alter table "ksef_direct_connections" add constraint "ksef_direct_connections_organization_id_tenant_id_unique" unique ("organization_id", "tenant_id");`);
|
|
7
|
+
}
|
|
8
|
+
down() {
|
|
9
|
+
this.addSql(`drop table if exists "ksef_direct_connections";`);
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
export {
|
|
13
|
+
Migration20260519210000_integration_ksef_direct
|
|
14
|
+
};
|
|
15
|
+
//# sourceMappingURL=Migration20260519210000_integration_ksef_direct.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../src/modules/integration_ksef_direct/migrations/Migration20260519210000_integration_ksef_direct.ts"],
|
|
4
|
+
"sourcesContent": ["import { Migration } from '@mikro-orm/migrations';\n\nexport class Migration20260519210000_integration_ksef_direct extends Migration {\n\n override up(): void | Promise<void> {\n this.addSql(`create table \"ksef_direct_connections\" (\"id\" uuid not null default gen_random_uuid(), \"organization_id\" uuid not null, \"tenant_id\" uuid not null, \"status\" text not null default 'unconfigured', \"last_checked_at\" timestamptz null, \"error_message\" text null, \"error_code\" text null, \"created_at\" timestamptz not null, \"updated_at\" timestamptz not null, primary key (\"id\"));`);\n this.addSql(`create index \"ksef_direct_connections_status_updated_at_index\" on \"ksef_direct_connections\" (\"status\", \"updated_at\");`);\n this.addSql(`alter table \"ksef_direct_connections\" add constraint \"ksef_direct_connections_organization_id_tenant_id_unique\" unique (\"organization_id\", \"tenant_id\");`);\n }\n\n override down(): void | Promise<void> {\n this.addSql(`drop table if exists \"ksef_direct_connections\";`);\n }\n\n}\n"],
|
|
5
|
+
"mappings": "AAAA,SAAS,iBAAiB;AAEnB,MAAM,wDAAwD,UAAU;AAAA,EAEpE,KAA2B;AAClC,SAAK,OAAO,oXAAoX;AAChY,SAAK,OAAO,uHAAuH;AACnI,SAAK,OAAO,0JAA0J;AAAA,EACxK;AAAA,EAES,OAA6B;AACpC,SAAK,OAAO,iDAAiD;AAAA,EAC/D;AAEF;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { Migration } from "@mikro-orm/migrations";
|
|
2
|
+
class Migration20260520120000_ksef_direct_documents extends Migration {
|
|
3
|
+
up() {
|
|
4
|
+
this.addSql(`create table "ksef_direct_documents" ("id" uuid not null default gen_random_uuid(), "organization_id" uuid not null, "tenant_id" uuid not null, "source" text not null default 'manual', "status" text not null default 'draft', "ksef_reference_number" text null, "seller_nip" text not null, "buyer_nip" text not null, "buyer_name" text null, "invoice_number" text not null, "issue_date" timestamptz not null, "sale_date" timestamptz null, "net_amount" numeric(15,2) not null, "vat_amount" numeric(15,2) not null, "gross_amount" numeric(15,2) not null, "currency" text not null default 'PLN', "line_items" jsonb not null default '[]', "notes" text null, "error_message" text null, "created_at" timestamptz not null, "updated_at" timestamptz not null, primary key ("id"));`);
|
|
5
|
+
this.addSql(`create index "ksef_direct_documents_organization_id_tenant_id_index" on "ksef_direct_documents" ("organization_id", "tenant_id");`);
|
|
6
|
+
this.addSql(`create index "ksef_direct_documents_organization_id_tenant_id_status_index" on "ksef_direct_documents" ("organization_id", "tenant_id", "status");`);
|
|
7
|
+
this.addSql(`create index "ksef_direct_documents_organization_id_tenant_id_source_index" on "ksef_direct_documents" ("organization_id", "tenant_id", "source");`);
|
|
8
|
+
this.addSql(`create index "ksef_direct_documents_ksef_reference_number_index" on "ksef_direct_documents" ("ksef_reference_number");`);
|
|
9
|
+
}
|
|
10
|
+
down() {
|
|
11
|
+
this.addSql(`drop table if exists "ksef_direct_documents";`);
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
export {
|
|
15
|
+
Migration20260520120000_ksef_direct_documents
|
|
16
|
+
};
|
|
17
|
+
//# sourceMappingURL=Migration20260520120000_ksef_direct_documents.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../src/modules/integration_ksef_direct/migrations/Migration20260520120000_ksef_direct_documents.ts"],
|
|
4
|
+
"sourcesContent": ["import { Migration } from '@mikro-orm/migrations';\n\nexport class Migration20260520120000_ksef_direct_documents extends Migration {\n\n override up(): void | Promise<void> {\n this.addSql(`create table \"ksef_direct_documents\" (\"id\" uuid not null default gen_random_uuid(), \"organization_id\" uuid not null, \"tenant_id\" uuid not null, \"source\" text not null default 'manual', \"status\" text not null default 'draft', \"ksef_reference_number\" text null, \"seller_nip\" text not null, \"buyer_nip\" text not null, \"buyer_name\" text null, \"invoice_number\" text not null, \"issue_date\" timestamptz not null, \"sale_date\" timestamptz null, \"net_amount\" numeric(15,2) not null, \"vat_amount\" numeric(15,2) not null, \"gross_amount\" numeric(15,2) not null, \"currency\" text not null default 'PLN', \"line_items\" jsonb not null default '[]', \"notes\" text null, \"error_message\" text null, \"created_at\" timestamptz not null, \"updated_at\" timestamptz not null, primary key (\"id\"));`);\n this.addSql(`create index \"ksef_direct_documents_organization_id_tenant_id_index\" on \"ksef_direct_documents\" (\"organization_id\", \"tenant_id\");`);\n this.addSql(`create index \"ksef_direct_documents_organization_id_tenant_id_status_index\" on \"ksef_direct_documents\" (\"organization_id\", \"tenant_id\", \"status\");`);\n this.addSql(`create index \"ksef_direct_documents_organization_id_tenant_id_source_index\" on \"ksef_direct_documents\" (\"organization_id\", \"tenant_id\", \"source\");`);\n this.addSql(`create index \"ksef_direct_documents_ksef_reference_number_index\" on \"ksef_direct_documents\" (\"ksef_reference_number\");`);\n }\n\n override down(): void | Promise<void> {\n this.addSql(`drop table if exists \"ksef_direct_documents\";`);\n }\n\n}\n"],
|
|
5
|
+
"mappings": "AAAA,SAAS,iBAAiB;AAEnB,MAAM,sDAAsD,UAAU;AAAA,EAElE,KAA2B;AAClC,SAAK,OAAO,iwBAAiwB;AAC7wB,SAAK,OAAO,mIAAmI;AAC/I,SAAK,OAAO,oJAAoJ;AAChK,SAAK,OAAO,oJAAoJ;AAChK,SAAK,OAAO,wHAAwH;AAAA,EACtI;AAAA,EAES,OAA6B;AACpC,SAAK,OAAO,+CAA+C;AAAA,EAC7D;AAEF;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { Migration } from "@mikro-orm/migrations";
|
|
2
|
+
class Migration20260520220000_ksef_direct_send_queue extends Migration {
|
|
3
|
+
up() {
|
|
4
|
+
this.addSql(`alter table "ksef_direct_documents" add column "ksef_processing_reference_number" text null;`);
|
|
5
|
+
this.addSql(`alter table "ksef_direct_documents" add column "seller_name" text null;`);
|
|
6
|
+
}
|
|
7
|
+
down() {
|
|
8
|
+
this.addSql(`alter table "ksef_direct_documents" drop column "ksef_processing_reference_number";`);
|
|
9
|
+
this.addSql(`alter table "ksef_direct_documents" drop column "seller_name";`);
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
export {
|
|
13
|
+
Migration20260520220000_ksef_direct_send_queue
|
|
14
|
+
};
|
|
15
|
+
//# sourceMappingURL=Migration20260520220000_ksef_direct_send_queue.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../src/modules/integration_ksef_direct/migrations/Migration20260520220000_ksef_direct_send_queue.ts"],
|
|
4
|
+
"sourcesContent": ["import { Migration } from '@mikro-orm/migrations';\n\nexport class Migration20260520220000_ksef_direct_send_queue extends Migration {\n\n override up(): void | Promise<void> {\n this.addSql(`alter table \"ksef_direct_documents\" add column \"ksef_processing_reference_number\" text null;`);\n this.addSql(`alter table \"ksef_direct_documents\" add column \"seller_name\" text null;`);\n }\n\n override down(): void | Promise<void> {\n this.addSql(`alter table \"ksef_direct_documents\" drop column \"ksef_processing_reference_number\";`);\n this.addSql(`alter table \"ksef_direct_documents\" drop column \"seller_name\";`);\n }\n\n}\n"],
|
|
5
|
+
"mappings": "AAAA,SAAS,iBAAiB;AAEnB,MAAM,uDAAuD,UAAU;AAAA,EAEnE,KAA2B;AAClC,SAAK,OAAO,8FAA8F;AAC1G,SAAK,OAAO,yEAAyE;AAAA,EACvF;AAAA,EAES,OAA6B;AACpC,SAAK,OAAO,qFAAqF;AACjG,SAAK,OAAO,gEAAgE;AAAA,EAC9E;AAEF;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { Migration } from "@mikro-orm/migrations";
|
|
2
|
+
class Migration20260520230000_ksef_direct_seller_per_document extends Migration {
|
|
3
|
+
up() {
|
|
4
|
+
this.addSql(`alter table "ksef_direct_documents" add column "seller_address_l1" text null;`);
|
|
5
|
+
this.addSql(`alter table "ksef_direct_documents" add column "seller_city" text null;`);
|
|
6
|
+
this.addSql(`alter table "ksef_direct_documents" add column "seller_country" text null;`);
|
|
7
|
+
}
|
|
8
|
+
down() {
|
|
9
|
+
this.addSql(`alter table "ksef_direct_documents" drop column "seller_address_l1";`);
|
|
10
|
+
this.addSql(`alter table "ksef_direct_documents" drop column "seller_city";`);
|
|
11
|
+
this.addSql(`alter table "ksef_direct_documents" drop column "seller_country";`);
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
export {
|
|
15
|
+
Migration20260520230000_ksef_direct_seller_per_document
|
|
16
|
+
};
|
|
17
|
+
//# sourceMappingURL=Migration20260520230000_ksef_direct_seller_per_document.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../src/modules/integration_ksef_direct/migrations/Migration20260520230000_ksef_direct_seller_per_document.ts"],
|
|
4
|
+
"sourcesContent": ["import { Migration } from '@mikro-orm/migrations';\n\nexport class Migration20260520230000_ksef_direct_seller_per_document extends Migration {\n\n override up(): void | Promise<void> {\n this.addSql(`alter table \"ksef_direct_documents\" add column \"seller_address_l1\" text null;`);\n this.addSql(`alter table \"ksef_direct_documents\" add column \"seller_city\" text null;`);\n this.addSql(`alter table \"ksef_direct_documents\" add column \"seller_country\" text null;`);\n }\n\n override down(): void | Promise<void> {\n this.addSql(`alter table \"ksef_direct_documents\" drop column \"seller_address_l1\";`);\n this.addSql(`alter table \"ksef_direct_documents\" drop column \"seller_city\";`);\n this.addSql(`alter table \"ksef_direct_documents\" drop column \"seller_country\";`);\n }\n\n}\n"],
|
|
5
|
+
"mappings": "AAAA,SAAS,iBAAiB;AAEnB,MAAM,gEAAgE,UAAU;AAAA,EAE5E,KAA2B;AAClC,SAAK,OAAO,+EAA+E;AAC3F,SAAK,OAAO,yEAAyE;AACrF,SAAK,OAAO,4EAA4E;AAAA,EAC1F;AAAA,EAES,OAA6B;AACpC,SAAK,OAAO,sEAAsE;AAClF,SAAK,OAAO,gEAAgE;AAC5E,SAAK,OAAO,mEAAmE;AAAA,EACjF;AAEF;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { Migration } from "@mikro-orm/migrations";
|
|
2
|
+
class Migration20260521120000_ksef_direct_received_documents extends Migration {
|
|
3
|
+
up() {
|
|
4
|
+
this.addSql(`create table "ksef_direct_received_documents" ("id" uuid not null default gen_random_uuid(), "organization_id" uuid not null, "tenant_id" uuid not null, "ksef_reference_number" text not null, "raw_xml" text null, "invoice_number" text null, "seller_nip" text null, "seller_name" text null, "issue_date" date null, "currency" text null, "net_amount" numeric(15,2) null, "vat_amount" numeric(15,2) null, "gross_amount" numeric(15,2) null, "status" text not null default 'pending_download', "error_message" text null, "upo_download_url" text null, "invoice_download_url" text null, "synced_at" timestamptz null, "created_at" timestamptz not null, "updated_at" timestamptz not null, primary key ("id"));`);
|
|
5
|
+
this.addSql(`create index "ksef_direct_received_documents_organization_id_tenant_id_index" on "ksef_direct_received_documents" ("organization_id", "tenant_id");`);
|
|
6
|
+
this.addSql(`create index "ksef_direct_received_documents_organization_id_tenant_id_status_index" on "ksef_direct_received_documents" ("organization_id", "tenant_id", "status");`);
|
|
7
|
+
this.addSql(`alter table "ksef_direct_received_documents" add constraint "ksef_direct_received_documents_organization_id_ksef_reference_number_unique" unique ("organization_id", "ksef_reference_number");`);
|
|
8
|
+
}
|
|
9
|
+
down() {
|
|
10
|
+
this.addSql(`drop table if exists "ksef_direct_received_documents";`);
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
export {
|
|
14
|
+
Migration20260521120000_ksef_direct_received_documents
|
|
15
|
+
};
|
|
16
|
+
//# sourceMappingURL=Migration20260521120000_ksef_direct_received_documents.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../src/modules/integration_ksef_direct/migrations/Migration20260521120000_ksef_direct_received_documents.ts"],
|
|
4
|
+
"sourcesContent": ["import { Migration } from '@mikro-orm/migrations';\n\nexport class Migration20260521120000_ksef_direct_received_documents extends Migration {\n\n override up(): void | Promise<void> {\n this.addSql(`create table \"ksef_direct_received_documents\" (\"id\" uuid not null default gen_random_uuid(), \"organization_id\" uuid not null, \"tenant_id\" uuid not null, \"ksef_reference_number\" text not null, \"raw_xml\" text null, \"invoice_number\" text null, \"seller_nip\" text null, \"seller_name\" text null, \"issue_date\" date null, \"currency\" text null, \"net_amount\" numeric(15,2) null, \"vat_amount\" numeric(15,2) null, \"gross_amount\" numeric(15,2) null, \"status\" text not null default 'pending_download', \"error_message\" text null, \"upo_download_url\" text null, \"invoice_download_url\" text null, \"synced_at\" timestamptz null, \"created_at\" timestamptz not null, \"updated_at\" timestamptz not null, primary key (\"id\"));`);\n this.addSql(`create index \"ksef_direct_received_documents_organization_id_tenant_id_index\" on \"ksef_direct_received_documents\" (\"organization_id\", \"tenant_id\");`);\n this.addSql(`create index \"ksef_direct_received_documents_organization_id_tenant_id_status_index\" on \"ksef_direct_received_documents\" (\"organization_id\", \"tenant_id\", \"status\");`);\n this.addSql(`alter table \"ksef_direct_received_documents\" add constraint \"ksef_direct_received_documents_organization_id_ksef_reference_number_unique\" unique (\"organization_id\", \"ksef_reference_number\");`);\n }\n\n override down(): void | Promise<void> {\n this.addSql(`drop table if exists \"ksef_direct_received_documents\";`);\n }\n\n}\n"],
|
|
5
|
+
"mappings": "AAAA,SAAS,iBAAiB;AAEnB,MAAM,+DAA+D,UAAU;AAAA,EAE3E,KAA2B;AAClC,SAAK,OAAO,6rBAA6rB;AACzsB,SAAK,OAAO,qJAAqJ;AACjK,SAAK,OAAO,sKAAsK;AAClL,SAAK,OAAO,gMAAgM;AAAA,EAC9M;AAAA,EAES,OAA6B;AACpC,SAAK,OAAO,wDAAwD;AAAA,EACtE;AAEF;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { Migration } from "@mikro-orm/migrations";
|
|
2
|
+
class Migration20260521130000_ksef_received_download_urls extends Migration {
|
|
3
|
+
up() {
|
|
4
|
+
this.addSql(`alter table "ksef_direct_received_documents" add column if not exists "upo_download_url" text null;`);
|
|
5
|
+
this.addSql(`alter table "ksef_direct_received_documents" add column if not exists "invoice_download_url" text null;`);
|
|
6
|
+
}
|
|
7
|
+
down() {
|
|
8
|
+
this.addSql(`alter table "ksef_direct_received_documents" drop column if exists "upo_download_url";`);
|
|
9
|
+
this.addSql(`alter table "ksef_direct_received_documents" drop column if exists "invoice_download_url";`);
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
export {
|
|
13
|
+
Migration20260521130000_ksef_received_download_urls
|
|
14
|
+
};
|
|
15
|
+
//# sourceMappingURL=Migration20260521130000_ksef_received_download_urls.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../src/modules/integration_ksef_direct/migrations/Migration20260521130000_ksef_received_download_urls.ts"],
|
|
4
|
+
"sourcesContent": ["import { Migration } from '@mikro-orm/migrations';\n\nexport class Migration20260521130000_ksef_received_download_urls extends Migration {\n\n override up(): void | Promise<void> {\n this.addSql(`alter table \"ksef_direct_received_documents\" add column if not exists \"upo_download_url\" text null;`);\n this.addSql(`alter table \"ksef_direct_received_documents\" add column if not exists \"invoice_download_url\" text null;`);\n }\n\n override down(): void | Promise<void> {\n this.addSql(`alter table \"ksef_direct_received_documents\" drop column if exists \"upo_download_url\";`);\n this.addSql(`alter table \"ksef_direct_received_documents\" drop column if exists \"invoice_download_url\";`);\n }\n\n}\n"],
|
|
5
|
+
"mappings": "AAAA,SAAS,iBAAiB;AAEnB,MAAM,4DAA4D,UAAU;AAAA,EAExE,KAA2B;AAClC,SAAK,OAAO,qGAAqG;AACjH,SAAK,OAAO,yGAAyG;AAAA,EACvH;AAAA,EAES,OAA6B;AACpC,SAAK,OAAO,wFAAwF;AACpG,SAAK,OAAO,4FAA4F;AAAA,EAC1G;AAEF;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../src/modules/integration_ksef_direct/setup.ts"],
|
|
4
|
+
"sourcesContent": ["import type { ModuleSetupConfig } from '@open-mercato/shared/modules/setup'\n\nexport const setup: ModuleSetupConfig = {\n defaultRoleFeatures: {\n admin: ['integration_ksef_direct.*'],\n },\n}\n\nexport default setup\n"],
|
|
5
|
+
"mappings": "AAEO,MAAM,QAA2B;AAAA,EACtC,qBAAqB;AAAA,IACnB,OAAO,CAAC,2BAA2B;AAAA,EACrC;AACF;AAEA,IAAO,gBAAQ;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { enqueueKsefDirectDocument } from "../commands/enqueue-ksef-direct-document.js";
|
|
2
|
+
const metadata = {
|
|
3
|
+
event: "ksef_direct.document.created",
|
|
4
|
+
persistent: true,
|
|
5
|
+
id: "ksef_direct.auto_enqueue_document"
|
|
6
|
+
};
|
|
7
|
+
async function handler(payload, ctx) {
|
|
8
|
+
const em = ctx.resolve("em")?.fork();
|
|
9
|
+
if (!em) return;
|
|
10
|
+
try {
|
|
11
|
+
await enqueueKsefDirectDocument(em, payload.tenantId, payload.organizationId, payload.documentId);
|
|
12
|
+
} catch {
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
export {
|
|
16
|
+
handler as default,
|
|
17
|
+
metadata
|
|
18
|
+
};
|
|
19
|
+
//# sourceMappingURL=auto-enqueue-ksef-document.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../src/modules/integration_ksef_direct/subscribers/auto-enqueue-ksef-document.ts"],
|
|
4
|
+
"sourcesContent": ["import { enqueueKsefDirectDocument } from '../commands/enqueue-ksef-direct-document'\n\nexport const metadata = {\n event: 'ksef_direct.document.created',\n persistent: true,\n id: 'ksef_direct.auto_enqueue_document',\n}\n\nexport default async function handler(\n payload: { documentId: string; organizationId: string; tenantId: string },\n ctx: { resolve: <T = unknown>(name: string) => T },\n) {\n const em = ctx.resolve<{ fork: () => unknown }>('em')?.fork() as any\n if (!em) return\n\n try {\n await enqueueKsefDirectDocument(em, payload.tenantId, payload.organizationId, payload.documentId)\n } catch {\n // If document is already queued or in a non-draft state, ignore \u2014 idempotent\n }\n}\n"],
|
|
5
|
+
"mappings": "AAAA,SAAS,iCAAiC;AAEnC,MAAM,WAAW;AAAA,EACtB,OAAO;AAAA,EACP,YAAY;AAAA,EACZ,IAAI;AACN;AAEA,eAAO,QACL,SACA,KACA;AACA,QAAM,KAAK,IAAI,QAAiC,IAAI,GAAG,KAAK;AAC5D,MAAI,CAAC,GAAI;AAET,MAAI;AACF,UAAM,0BAA0B,IAAI,QAAQ,UAAU,QAAQ,gBAAgB,QAAQ,UAAU;AAAA,EAClG,QAAQ;AAAA,EAER;AACF;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|