diff --git a/CLAUDE.md b/CLAUDE.md index 0296a88..eab661f 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -27,7 +27,11 @@ wrap it as a leaf dependency. Do not couple it to any framework. (valibot). This is the single input type consumers construct. - `src/lib/eslog/` — **owned** e-SLOG 2.0 serializer: domain model → e-SLOG XML (UN/EDIFACT-INVOIC-derived, `urn:eslog:2.00`). This is the Slovenian delta the - upstream lib does not provide. + upstream lib does not provide. `validate-eslog.ts` validates produced XML + against the official XSD in `schema/` (`eSLOG20_INVOIC_v200.xsd` + + `xmldsig-core-schema.xsd`, vendored from epos.si) via `xmllint-wasm`. The XSDs + are loaded with bun text imports (`with { type: "text" }`; see `src/types.d.ts`) + so they ship in the package and work with no build step. - `src/lib/einvoice/` — bridge to `@e-invoice-eu/core`: maps the domain model → the lib's UBL-shaped internal JSON (`ubl:Invoice` / `cbc:`/`cac:`) → UBL / CII output, plus EN16931 validation via the lib's `invoiceSchema`. diff --git a/README.md b/README.md index eea7053..040cf70 100644 --- a/README.md +++ b/README.md @@ -97,6 +97,24 @@ const program = Effect.gen(function* () { `serializeEslog(invoice)` is a pure synchronous escape hatch for e-SLOG only. +### Validate produced e-SLOG against the official XSD + +```ts +import { generateEInvoice, validateEslogXml } from "@grunt-it/fiscalize"; + +// validate on the way out… +const xml = await Effect.runPromise( + generateEInvoice(invoice, { format: "eslog", validateOutput: true }), +); + +// …or validate any e-SLOG XML string standalone +yield* validateEslogXml(someEslogXml); +``` + +`validateEslogXml` checks the XML against the **official e-SLOG 2.0 XSD** +(`eSLOG20_INVOIC_v200.xsd` + `xmldsig-core-schema.xsd`, from the epos.si Aug-2020 +package), using xmllint compiled to WebAssembly — no native bindings. + ## The model `Invoice` is a clean, EN16931-aligned **core invoice**: header (BT-1/2/3/5/9/72), @@ -106,12 +124,13 @@ the mapping to each syntax stays auditable. Validated with `valibot`. ## What's covered vs deferred -P1 maps the **mandatory + common core**. Document-level allowances/charges, -line-level allowances, contacts, multiple payment means, e-SLOG XSD/schematron -output validation, and the long tail of optional BTs are deferred — see -[`ROADMAP.md`](./ROADMAP.md). The e-SLOG mapping is grounded in the official -spec (epos.si) and cross-checked against the MIT-licensed reference generator -`Media24si/eslog2`. +P1 maps the **mandatory + common core**, and produced e-SLOG XML is validated +against the official e-SLOG 2.0 **XSD**. Deferred (see [`ROADMAP.md`](./ROADMAP.md)): +business-rule (schematron-equivalent) validation — the official package ships no +`.sch`, so those rules are spec prose — plus document/line-level allowances, +contacts, multiple payment means, and the long tail of optional BTs. The e-SLOG +mapping is grounded in the official spec (epos.si) and cross-checked against the +MIT-licensed reference generator `Media24si/eslog2`. ## Development diff --git a/ROADMAP.md b/ROADMAP.md index 3ea4eff..ab18945 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -14,12 +14,23 @@ EN16931 core invoice → **e-SLOG 2.0** + **UBL / CII**, with validation. - EN16931 structural validation via the lib's JSON Schema (Ajv 2019-09). - Effect-native API + Promise boundary (`createEInvoice`). +## P1.x — e-SLOG XSD output validation ✅ + +- `validateEslogXml(xml)` validates produced e-SLOG XML against the **official + e-SLOG 2.0 XSD** (`eSLOG20_INVOIC_v200.xsd` + its `xmldsig-core-schema.xsd` + import), vendored from the epos.si Aug-2020 package, via xmllint compiled to + WebAssembly (`xmllint-wasm` — no native bindings, bun-friendly). +- `generateEInvoice(..., { validateOutput: true })` validates before returning. +- Confirms the P1 serializer is **XSD-conformant** (regression-locked in tests + against both our output and the official sample invoice). + ### Deferred within the e-invoice core (next P1.x slices) -- **e-SLOG XSD + schematron validation** of *output*. P1 validates the EN16931 - model structurally (UBL schema); it does not yet validate the produced e-SLOG - XML against the official e-SLOG 2.0 XSD or business-rule schematron. Vendor the - XSD (incl. `xmldsig-core-schema.xsd`) and add an output-validation pass. +- **Business-rule (schematron-equivalent) validation.** The official e-SLOG 2.0 + package ships **no `.sch`** — the business rules (arithmetic, conditional + presence) live in the spec PDFs as prose. The XSD enforces structure/types, + not those rules. A future slice can encode the key rules (BR-CO/BR-S analogues) + as checks. Cross-check against the lib's EN16931 schematron where it overlaps. - **Document-level allowances/charges** (BG-20/BG-21) → e-SLOG `G_SG16`, UBL `cac:AllowanceCharge`. Model has the totals (BT-107/108) but not the detail. - **Line-level allowances** (BG-27/BG-28) → e-SLOG `G_SG39`. diff --git a/bun.lock b/bun.lock index ddfb788..a0931ce 100644 --- a/bun.lock +++ b/bun.lock @@ -11,6 +11,7 @@ "effect": "^3.18.4", "valibot": "^1.2.0", "xmlbuilder2": "^4.0.3", + "xmllint-wasm": "^5.2.0", }, "devDependencies": { "@types/bun": "latest", @@ -110,5 +111,7 @@ "valibot": ["valibot@1.4.1", "", { "peerDependencies": { "typescript": ">=5" }, "optionalPeers": ["typescript"] }, "sha512-klCmFTz2jeDluy9RwX+F884TCiogtdBJ/YaxSx1EOBYXa3NXNWj8kR1jjN8rzluwojJVWWaHJ4r1U5LfICnM3g=="], "xmlbuilder2": ["xmlbuilder2@4.0.3", "", { "dependencies": { "@oozcitak/dom": "^2.0.2", "@oozcitak/infra": "^2.0.2", "@oozcitak/util": "^10.0.0", "js-yaml": "^4.1.1" } }, "sha512-bx8Q1STctnNaaDymWnkfQLKofs0mGNN7rLLapJlGuV3VlvegD7Ls4ggMjE3aUSWItCCzU0PEv45lI87iSigiCA=="], + + "xmllint-wasm": ["xmllint-wasm@5.2.0", "", { "peerDependencies": { "@types/node": ">=16" } }, "sha512-GVMuR3ViU8R7sakcVm/4GClMtCV8p7xgjXZlc6GmvPpInIz4V41lmRnjSd4uKhVkf5MZj97wEZkPM4RMAhojuQ=="], } } diff --git a/package.json b/package.json index aa407dc..9663a55 100644 --- a/package.json +++ b/package.json @@ -55,6 +55,7 @@ "ajv-formats": "^3.0.1", "effect": "^3.18.4", "valibot": "^1.2.0", - "xmlbuilder2": "^4.0.3" + "xmlbuilder2": "^4.0.3", + "xmllint-wasm": "^5.2.0" } } diff --git a/src/index.ts b/src/index.ts index 27655df..a1fa9bf 100644 --- a/src/index.ts +++ b/src/index.ts @@ -41,4 +41,5 @@ export * from "./lib/foundation"; export * from "./lib/invoice"; export * from "./lib/einvoice"; export { type EslogOptions, serializeEslog } from "./lib/eslog/serialize"; +export { validateEslogXml } from "./lib/eslog/validate-eslog"; export * as eslogCodes from "./lib/eslog/codes"; diff --git a/src/lib/einvoice/generate.ts b/src/lib/einvoice/generate.ts index 07aa2be..b6cd4c5 100644 --- a/src/lib/einvoice/generate.ts +++ b/src/lib/einvoice/generate.ts @@ -3,6 +3,7 @@ import { Effect } from "effect"; import { EInvoiceGenerationError, UnsupportedFormatError } from "../foundation/errors"; import type { EslogOptions } from "../eslog/serialize"; import { serializeEslog } from "../eslog/serialize"; +import { validateEslogXml } from "../eslog/validate-eslog"; import type { Invoice } from "../invoice/model"; import { FORMATS, type Format, isFormat, LIB_FORMAT } from "./formats"; import { toEInvoiceInternal } from "./to-internal"; @@ -14,6 +15,12 @@ export interface GenerateOptions extends EslogOptions { * Factur-X PDF metadata; irrelevant to the pure-XML formats here. Default `sl`. */ lang?: string; + /** + * For `eslog`: validate the produced XML against the official e-SLOG 2.0 XSD + * before returning (fails with `EslogValidationError` if non-conformant). + * Default `false`. Ignored for `ubl`/`cii` (the lib validates those itself). + */ + validateOutput?: boolean; } // `InvoiceService` is stateless across calls; build once. @@ -42,10 +49,12 @@ export const generateEInvoice = Effect.fn("generateEInvoice")(function* ( } if (format === "eslog") { - return yield* Effect.try({ + const xml = yield* Effect.try({ try: () => serializeEslog(invoice, options), catch: (cause) => new EInvoiceGenerationError("eslog", cause), }); + if (options.validateOutput) yield* validateEslogXml(xml); + return xml; } const internal = toEInvoiceInternal(invoice) as unknown as EInvoiceEUInvoice; diff --git a/src/lib/eslog/index.ts b/src/lib/eslog/index.ts index c54d05f..ed529db 100644 --- a/src/lib/eslog/index.ts +++ b/src/lib/eslog/index.ts @@ -1,2 +1,3 @@ export * from "./serialize"; +export * from "./validate-eslog"; export * as eslogCodes from "./codes"; diff --git a/src/lib/eslog/schema/PROVENANCE.md b/src/lib/eslog/schema/PROVENANCE.md new file mode 100644 index 0000000..b47fa1f --- /dev/null +++ b/src/lib/eslog/schema/PROVENANCE.md @@ -0,0 +1,19 @@ +# Vendored e-SLOG 2.0 schema — provenance + +These files are the **official** e-SLOG 2.0 invoice schema, unmodified, vendored +from the e-SLOG 2.0 (August 2020) documentation package published by the +Slovenian national eBusiness centre (ePOS / GZS): + +- Source: → `e-SLOG-2.0-08-2020-EN.zip` +- `eSLOG20_INVOIC_v200.xsd` — invoice (eRačun) XML schema, namespace `urn:eslog:2.00`. +- `xmldsig-core-schema.xsd` — W3C XML-Signature schema imported by the above + (`http://www.w3.org/2000/09/xmldsig#`). + +They are used at runtime by `../validate-eslog.ts` to validate produced e-SLOG +XML. The official sample invoice from the same package is kept (as a test +fixture) at `src/test/sample-eslog20-with-bt.xml`, and the 1.6↔2.0 mapping +tables ship in the package as `.xlsx` (not vendored here). + +e-SLOG is an open standard for Slovenian electronic business documents; these +schema files are redistributed for interoperability. They are not covered by +this project's MIT license — refer to ePOS/GZS for their terms. diff --git a/src/lib/eslog/schema/eSLOG20_INVOIC_v200.xsd b/src/lib/eslog/schema/eSLOG20_INVOIC_v200.xsd new file mode 100644 index 0000000..9894b52 --- /dev/null +++ b/src/lib/eslog/schema/eSLOG20_INVOIC_v200.xsd @@ -0,0 +1,2086 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/lib/eslog/schema/xmldsig-core-schema.xsd b/src/lib/eslog/schema/xmldsig-core-schema.xsd new file mode 100644 index 0000000..c75f123 --- /dev/null +++ b/src/lib/eslog/schema/xmldsig-core-schema.xsd @@ -0,0 +1,318 @@ + + + + + + ]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/lib/eslog/validate-eslog.ts b/src/lib/eslog/validate-eslog.ts new file mode 100644 index 0000000..c188d41 --- /dev/null +++ b/src/lib/eslog/validate-eslog.ts @@ -0,0 +1,40 @@ +import { Effect } from "effect"; +import { validateXML } from "xmllint-wasm"; +import { EInvoiceGenerationError, EslogValidationError, type ValidationIssue } from "../foundation/errors"; +import invoiceXsd from "./schema/eSLOG20_INVOIC_v200.xsd" with { type: "text" }; +import xmldsigXsd from "./schema/xmldsig-core-schema.xsd" with { type: "text" }; + +/** + * Validate an e-SLOG XML string against the **official e-SLOG 2.0 XSD** + * (`eSLOG20_INVOIC_v200.xsd`, with its `xmldsig-core-schema.xsd` import), + * vendored from the epos.si August-2020 package. + * + * Uses xmllint compiled to WebAssembly — no native bindings, bun-friendly. + * Succeeds with the input XML; fails with `EslogValidationError` listing the + * schema violations (line-located where xmllint reports them). + * + * This is *output* validation (the produced XML is schema-conformant), distinct + * from `validateEn16931` which validates the EN16931 model structurally. Note: + * the e-SLOG XSD enforces structure/types, not the business-rule arithmetic in + * the spec prose (no official schematron is published) — see ROADMAP.md. + */ +export const validateEslogXml = Effect.fn("validateEslogXml")(function* (xml: string) { + const result = yield* Effect.tryPromise({ + try: () => + validateXML({ + xml: [{ fileName: "invoice.xml", contents: xml }], + schema: [{ fileName: "eSLOG20_INVOIC_v200.xsd", contents: invoiceXsd }], + // The XSD imports xmldsig by relative schemaLocation; provide it in the FS. + preload: [{ fileName: "xmldsig-core-schema.xsd", contents: xmldsigXsd }], + }), + catch: (cause) => new EInvoiceGenerationError("eslog", cause), + }); + + if (result.valid) return xml; + + const issues: ValidationIssue[] = result.errors.map((e) => ({ + path: e.loc ? `${e.loc.fileName}:${e.loc.lineNumber}` : "", + message: e.message, + })); + return yield* Effect.fail(new EslogValidationError(issues)); +}); diff --git a/src/lib/foundation/errors.ts b/src/lib/foundation/errors.ts index 6eaa10c..180a2a6 100644 --- a/src/lib/foundation/errors.ts +++ b/src/lib/foundation/errors.ts @@ -63,10 +63,28 @@ export class UnsupportedFormatError extends Data.TaggedError("UnsupportedFormatE } } +/** + * Produced e-SLOG XML failed validation against the official e-SLOG 2.0 XSD. + * 422-class: the document is well-formed but not schema-conformant — almost + * always a serializer/mapping gap, surfaced with the XSD errors. + */ +export class EslogValidationError extends Data.TaggedError("EslogValidationError")< + FiscalizeErrorParams & { issues: ValidationIssue[] } +> { + constructor(issues: ValidationIssue[]) { + super({ + message: `Produced e-SLOG XML failed e-SLOG 2.0 XSD validation (${issues.length} issue${issues.length === 1 ? "" : "s"}).`, + status: 422, + issues, + }); + } +} + export type FiscalizeError = | InvalidInvoiceError | EInvoiceGenerationError - | UnsupportedFormatError; + | UnsupportedFormatError + | EslogValidationError; function describe(cause: unknown): string { if (cause instanceof Error) return cause.message; diff --git a/src/test/eslog-xsd.test.ts b/src/test/eslog-xsd.test.ts new file mode 100644 index 0000000..9b9781d --- /dev/null +++ b/src/test/eslog-xsd.test.ts @@ -0,0 +1,43 @@ +import { describe, expect, test } from "bun:test"; +import { Effect } from "effect"; +import { generateEInvoice } from "../lib/einvoice/generate"; +import { serializeEslog } from "../lib/eslog/serialize"; +import { validateEslogXml } from "../lib/eslog/validate-eslog"; +import { EslogValidationError } from "../lib/foundation/errors"; +import { sampleInvoice } from "./fixtures"; + +describe("validateEslogXml (official e-SLOG 2.0 XSD)", () => { + test("our serializer output is conformant to the official XSD", async () => { + const xml = serializeEslog(sampleInvoice()); + const out = await Effect.runPromise(validateEslogXml(xml)); + expect(out).toBe(xml); + }); + + test("the official sample invoice validates (XSD harness sanity)", async () => { + const sample = await Bun.file(`${import.meta.dir}/sample-eslog20-with-bt.xml`).text(); + await Effect.runPromise(validateEslogXml(sample)); + }); + + test("a schema-violating document fails with EslogValidationError + issues", async () => { + // Inject a bogus element that the XSD does not allow. + const broken = serializeEslog(sampleInvoice()).replace( + "nope { + test("eslog + validateOutput returns the validated XML", async () => { + const xml = await Effect.runPromise( + generateEInvoice(sampleInvoice(), { format: "eslog", validateOutput: true }), + ); + expect(xml).toContain('xmlns="urn:eslog:2.00"'); + }); +}); diff --git a/src/test/sample-eslog20-with-bt.xml b/src/test/sample-eslog20-with-bt.xml new file mode 100644 index 0000000..10d8649 --- /dev/null +++ b/src/test/sample-eslog20-with-bt.xml @@ -0,0 +1,1422 @@ + + + + + TOSL110 + + INVOIC + D + 01B + UN + + + + + + 380 + + + + TOSL110 + + + + + 137 + + 2013-04-10 + + + + + 131 + + 2013-04-10 + + + + + 35 + + + + + 35 + + 2013-04-15 + + + + + 167 + + 2013-03-10 + + + + + 168 + + 2013-04-10 + + + + AAB + + + 50% prepaid, 50% within one month + Additional text line 2 + Additional text line 3 + Additional text line 4 + Additional text line 5 + + + + REG + + + Export + + + + + GEN + + + Ordered through our website + + + + DOC + + + P1 + + + + urn:cen.eu:en16931:2017 + + + + AAT + + + Half prepaid + + + + AGM + + + vatex-eu-ae + + + + Exempt New Means of Transport + + + + PMD + + TOSL110 + + + + TXD + + + 2013-04-10T15:03:50 + + PRODAJALEC1 + + 56dcaf93-933a-497d-b864-0ba1e8f4fa23 + + 8402f0a963e37b2258e034fc8ae7ffc1 + + 279042272585972554922067893753871413584876543211601021503002 + + + + PAI + + + 0 + + + + ALQ + + + OTHR + + + + + + AEP + + Project345 + + + + + + + CT + + 2013-05 + + + + + + + ON + + PO4711 + + + + + + + VN + + 123 + + + + + + + ALO + + 3544 + + + + + + + AAK + + 5433 + + + + + + + GC + + Lot567 + + + + + + + + ATS + + OBJ999 + + + + + + + OI + + TOSL109 + + + + + 384 + + 2013-03-10 + + + + + + + PQ + + Payref1 + + + + + + BY + + + 5790000436057 + + 0088 + + + + BuyerCompany ltd + + Buyco + + + + Anystreet, Building 1 + + 5th floor + + 5th door + + + Anytown + + + Jutland + + + 101 + + DK + + + PB + + + 510510******5100 + + John hansen + + + + BI + + + DK1212341234123412 + + + + BB + + + DK1212341234123412 + + BuyerCompany ltd + + + + DNBANOKK + + + + + + CR + + qwerty + + + + + + + AOU + + 67543 + + + + + + + + 0199 + + DK16356607 + + + + + + + VA + + DK16356607 + + + + + + + AHP + + DK16356607 + + + + + + + AVS + + 123456 + + + + + + + AII + + DK5678 + + + + + + IC + + + + + info@buyercompany.dk + + EM + + + + + + PD + + + John Hansen + + + + + + info@buyercompany.dk + EM + + + + + + 4598989898 + TE + + + + + + + SE + + + 5790000434101 + + 0088 + + + + SellerCompany + + SelCo + + + + Hoofdstraat 4 + + Om de hoek + + Om de hoek 2 + + + Grootstad + + + Overijssel + + + 54321 + + NL + + + RB + + + DK1212341234123412 + + SellerCompany + + + + DNBANOKK + + + + + + + 0199 + + NL16356706 + + + + + + + VA + + NL16356706 + + + + + + + AHP + + NL16356706 + + + + + + IC + + + + + info@selco.nl + + EM + + + + + + SU + + + Anthon Larsen + + + + + + 3198989898 + TE + + + + + + anthon@selco.nl + EM + + + + + + + PE + + + DK16356608 + + 0088 + + + + Dagober Duck + + + + + + + 0199 + + DK16356608 + + + + + + + DP + + + 579000436068 + + 0088 + + + + Logistic service ltd + + + + Delivery street + + Gate 15 + + Floor 2 + + + Delivery city + + + Jutland + + + 9000 + + DK + + + + + LC + + + Dick Panama + + + + AnyStreet, buliding 1 + + 6th floor + + 6th door + + + Anytown + + + Jutland + + + 101 + + DK + + + + + VA + + DK16356609 + + + + + + + + 2 + + DKK + + + + + + + 6 + + EUR + + + + + + 1 + + + + 13 + + 2013-05-10 + + + + + + 30 + + + + + + A + + + Loyal customer + + 42 + + + + + + 1 + + 10 + + + + + + + 204 + + 150.00 + + + + + + + 25 + + 1500.00 + + + + + + 7 + + VAT + + + + 25 + + + S + + + + + + C + + + Packaging + + + + ABL + + + + + + 2 + + 10 + + + + + + + 23 + + 150.00 + + + + + + + 25 + + 1500.00 + + + + + + 7 + + VAT + + + + 25 + + + S + + + + + + + 1 + + + 1234567890128 + + 0160 + + + + 5 + + + JB007 + SA + + + + 5 + + + BUY123 + IN + + + + 1 + + + 123444321 + + ZZZ + + + + F + + + Printing paper + + + + A + + + printing paper, 2mm + + + + + 47 + + 1000 + + C62 + + + + + NL + + + + 167 + + 2013-03-10 + + + + + 168 + + 2013-04-10 + + + + ACB + + + first line + + + + ACF + + + Thickness + + 2 mm + + + + + + 203 + + 1000.00 + + + + + + + 38 + + 1250.00 + + + + + + + AAA + + 1.0000 + + 1 + + C62 + + + + + + + AAB + + 1.1000 + + 1 + + C62 + + + + + + + + AVE + + Object 2 + + + + + + + ON + + 1 + + + + + + + AWQ + + ACC7654 + + + + + + 7 + + VAT + + + + 25 + + + S + + + + 125 + + 1000.00 + + + + + 124 + + 250.00 + + + + + + A + + + Loyal customer + + 95 + + + + + + 1 + + 10 + + + + + + + 204 + + 100.00 + + + + + + + 25 + + 1000.00 + + + + + + + A + + + + + 509 + + 0.1000 + + + + + + + C + + + Packaging + + + + ABL + + + + + + 2 + + 10 + + + + + + + 23 + + 100.00 + + + + + + + 25 + + 1000.00 + + + + + + + + 2 + + + 5 + + JB008 + SA + + + + F + + Parker Pen + + + + A + + Perker Pen, Black, model Sansa + + + + + 47 + 100 + C62 + + + + NL + + + + 167 + 2013-03-10 + + + + + 168 + 2013-04-10 + + + + ACB + + Second line + + + + + + 203 + 500.00 + + + + + + + 38 + 625.00 + + + + + + + AAA + 5.0000 + + + + + + + AVE + Object 2 + + + + + + + ON + 2 + + + + + + + AWQ + ACC7654 + + + + + + 7 + + VAT + + + 25 + + S + + + + 125 + 500.00 + + + + + 124 + 125.00 + + + + + + + 3 + + + 5 + + JB009 + SA + + + + F + + American Cookies + + + + + 47 + 500 + C62 + + + + + + 203 + 2500.00 + + + + + + + 38 + 2800.00 + + + + + + + AAA + 5.0000 + + + + + + 7 + + VAT + + + 12 + + S + + + + 125 + 2500.00 + + + + + 124 + 300.00 + + + + + + D + + + + + 79 + + 4000.00 + + + + + + + 389 + + 4000.00 + + + + + + + 388 + + 4675.00 + + + + + + + 9 + + 2337.50 + + + + + + + 260 + + 150.00 + + + + + + + 259 + + 150.00 + + + + + + + 2 + + 628.62 + + + + + + + 113 + + 2337.50 + + + + + + + 366 + + 0 + + + + + + + 176 + + 675.00 + + + + + + 7 + + VAT + + + + 25 + + + S + + + + 125 + + 1500.00 + + + + + 124 + + 375.00 + + + + + + 7 + + VAT + + + + 12 + + + S + + + + 125 + + 2500.00 + + + + + 124 + + 300.00 + + + + + + 7 + + OTH + + + + 12 + + + + + 125 + + 2500.00 + + + + + 124 + + 300.00 + + + + + \ No newline at end of file diff --git a/src/types.d.ts b/src/types.d.ts new file mode 100644 index 0000000..17b8fb0 --- /dev/null +++ b/src/types.d.ts @@ -0,0 +1,5 @@ +// Text imports of vendored schema files (bun: `import x from "./f.xsd" with { type: "text" }`). +declare module "*.xsd" { + const content: string; + export default content; +}