fix(core): Refactor module imports to use the centralized plugins module and update relative paths across the codebase. Also remove the obsolete test file (test/test.other-formats-corpus.ts) and update file metadata in test outputs.
This commit is contained in:
@ -3,6 +3,6 @@
|
||||
*/
|
||||
export const commitinfo = {
|
||||
name: '@fin.cx/xinvoice',
|
||||
version: '4.1.2',
|
||||
version: '4.1.3',
|
||||
description: 'A TypeScript module for creating, manipulating, and embedding XML data within PDF files specifically tailored for xinvoice packages.'
|
||||
}
|
||||
|
@ -1,4 +1,6 @@
|
||||
import { business, finance } from '@tsclass/tsclass';
|
||||
import * as plugins from './plugins.js';
|
||||
|
||||
import { business, finance } from './plugins.js';
|
||||
import type { TInvoice } from './interfaces/common.js';
|
||||
import { InvoiceFormat, ValidationLevel } from './interfaces/common.js';
|
||||
import type { ValidationResult, ValidationError, XInvoiceOptions, IPdf, ExportFormat } from './interfaces/common.js';
|
||||
|
@ -1,8 +1,7 @@
|
||||
import { BaseDecoder } from '../base/base.decoder.js';
|
||||
import type { TInvoice, TCreditNote, TDebitNote } from '../../interfaces/common.js';
|
||||
import { CII_NAMESPACES, CIIProfile } from './cii.types.js';
|
||||
import { DOMParser } from 'xmldom';
|
||||
import * as xpath from 'xpath';
|
||||
import { DOMParser, xpath } from '../../plugins.js';
|
||||
|
||||
/**
|
||||
* Base decoder for CII-based invoice formats
|
||||
|
@ -2,8 +2,7 @@ import { BaseValidator } from '../base/base.validator.js';
|
||||
import { ValidationLevel } from '../../interfaces/common.js';
|
||||
import type { ValidationResult } from '../../interfaces/common.js';
|
||||
import { CII_NAMESPACES, CIIProfile } from './cii.types.js';
|
||||
import { DOMParser } from 'xmldom';
|
||||
import * as xpath from 'xpath';
|
||||
import { DOMParser, xpath } from '../../plugins.js';
|
||||
|
||||
/**
|
||||
* Base validator for CII-based invoice formats
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { CIIBaseDecoder } from '../cii.decoder.js';
|
||||
import type { TInvoice, TCreditNote, TDebitNote } from '../../../interfaces/common.js';
|
||||
import { FACTURX_PROFILE_IDS } from './facturx.types.js';
|
||||
import { business, finance, general } from '@tsclass/tsclass';
|
||||
import { business, finance, general } from '../../../plugins.js';
|
||||
|
||||
/**
|
||||
* Decoder for Factur-X invoice format
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { CIIBaseEncoder } from '../cii.encoder.js';
|
||||
import type { TInvoice, TCreditNote, TDebitNote } from '../../../interfaces/common.js';
|
||||
import { FACTURX_PROFILE_IDS } from './facturx.types.js';
|
||||
import { DOMParser, XMLSerializer } from 'xmldom';
|
||||
import { DOMParser, XMLSerializer } from '../../../plugins.js';
|
||||
|
||||
/**
|
||||
* Encoder for Factur-X invoice format
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { CIIBaseDecoder } from '../cii.decoder.js';
|
||||
import type { TInvoice, TCreditNote, TDebitNote } from '../../../interfaces/common.js';
|
||||
import { business, finance } from '@tsclass/tsclass';
|
||||
import { business, finance } from '../../../plugins.js';
|
||||
|
||||
/**
|
||||
* Decoder for ZUGFeRD invoice format
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { CIIBaseDecoder } from '../cii.decoder.js';
|
||||
import type { TInvoice, TCreditNote, TDebitNote } from '../../../interfaces/common.js';
|
||||
import { ZUGFERD_V1_NAMESPACES } from '../cii.types.js';
|
||||
import { business, finance } from '@tsclass/tsclass';
|
||||
import { business, finance } from '../../../plugins.js';
|
||||
|
||||
/**
|
||||
* Decoder for ZUGFeRD v1 invoice format
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { PDFDocument, PDFDict, PDFName, PDFRawStream, PDFArray, PDFString } from 'pdf-lib';
|
||||
import { PDFDocument, PDFDict, PDFName, PDFRawStream, PDFArray, PDFString } from '../../../plugins.js';
|
||||
import { BaseXMLExtractor } from './base.extractor.js';
|
||||
|
||||
/**
|
||||
@ -15,48 +15,48 @@ export class AssociatedFilesExtractor extends BaseXMLExtractor {
|
||||
public async extractXml(pdfBuffer: Uint8Array | Buffer): Promise<string | null> {
|
||||
try {
|
||||
const pdfDoc = await PDFDocument.load(pdfBuffer);
|
||||
|
||||
|
||||
// Try to find associated files via the AF entry in the catalog
|
||||
const afArray = pdfDoc.catalog.lookup(PDFName.of('AF'));
|
||||
if (!(afArray instanceof PDFArray)) {
|
||||
console.warn('No AF (Associated Files) entry found in PDF catalog');
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
// Process each associated file
|
||||
for (let i = 0; i < afArray.size(); i++) {
|
||||
const fileSpec = afArray.lookup(i);
|
||||
if (!(fileSpec instanceof PDFDict)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
// Get the file name
|
||||
const fileNameObj = fileSpec.lookup(PDFName.of('F')) || fileSpec.lookup(PDFName.of('UF'));
|
||||
if (!(fileNameObj instanceof PDFString)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
const fileName = fileNameObj.decodeText();
|
||||
|
||||
|
||||
// Check if it's a known invoice XML file name
|
||||
const isKnownFileName = this.knownFileNames.some(
|
||||
knownName => fileName.toLowerCase() === knownName.toLowerCase()
|
||||
);
|
||||
|
||||
|
||||
// Check if it's any XML file or has invoice-related keywords
|
||||
const isXmlFile = fileName.toLowerCase().endsWith('.xml') ||
|
||||
const isXmlFile = fileName.toLowerCase().endsWith('.xml') ||
|
||||
fileName.toLowerCase().includes('zugferd') ||
|
||||
fileName.toLowerCase().includes('factur-x') ||
|
||||
fileName.toLowerCase().includes('xrechnung') ||
|
||||
fileName.toLowerCase().includes('invoice');
|
||||
|
||||
|
||||
if (isKnownFileName || isXmlFile) {
|
||||
// Get the embedded file dictionary
|
||||
const efDict = fileSpec.lookup(PDFName.of('EF'));
|
||||
if (!(efDict instanceof PDFDict)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
// Get the file stream
|
||||
const fileStream = efDict.lookup(PDFName.of('F'));
|
||||
if (fileStream instanceof PDFRawStream) {
|
||||
@ -67,7 +67,7 @@ export class AssociatedFilesExtractor extends BaseXMLExtractor {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
console.warn('No valid XML found in associated files');
|
||||
return null;
|
||||
} catch (error) {
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { PDFDocument, PDFDict, PDFName, PDFRawStream, PDFArray, PDFString } from 'pdf-lib';
|
||||
import { PDFDocument, PDFDict, PDFName, PDFRawStream, PDFArray, PDFString } from '../../../plugins.js';
|
||||
import { BaseXMLExtractor } from './base.extractor.js';
|
||||
|
||||
/**
|
||||
@ -47,19 +47,19 @@ export class StandardXMLExtractor extends BaseXMLExtractor {
|
||||
|
||||
// Get the filename as string
|
||||
const fileName = fileNameObj.decodeText();
|
||||
|
||||
|
||||
// Check if it's a known invoice XML file name
|
||||
const isKnownFileName = this.knownFileNames.some(
|
||||
knownName => fileName.toLowerCase() === knownName.toLowerCase()
|
||||
);
|
||||
|
||||
|
||||
// Check if it's any XML file or has invoice-related keywords
|
||||
const isXmlFile = fileName.toLowerCase().endsWith('.xml') ||
|
||||
const isXmlFile = fileName.toLowerCase().endsWith('.xml') ||
|
||||
fileName.toLowerCase().includes('zugferd') ||
|
||||
fileName.toLowerCase().includes('factur-x') ||
|
||||
fileName.toLowerCase().includes('xrechnung') ||
|
||||
fileName.toLowerCase().includes('invoice');
|
||||
|
||||
|
||||
if (isKnownFileName || isXmlFile) {
|
||||
const efDictObj = fileSpecObj.lookup(PDFName.of('EF'));
|
||||
if (!(efDictObj instanceof PDFDict)) {
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { PDFDocument, AFRelationship } from 'pdf-lib';
|
||||
import { PDFDocument, AFRelationship } from '../../plugins.js';
|
||||
import type { IPdf } from '../../interfaces/common.js';
|
||||
|
||||
/**
|
||||
|
@ -1,8 +1,7 @@
|
||||
import { BaseDecoder } from '../base/base.decoder.js';
|
||||
import type { TInvoice, TCreditNote, TDebitNote } from '../../interfaces/common.js';
|
||||
import { UBLDocumentType, UBL_NAMESPACES } from './ubl.types.js';
|
||||
import { DOMParser } from 'xmldom';
|
||||
import * as xpath from 'xpath';
|
||||
import { DOMParser, xpath } from '../../plugins.js';
|
||||
|
||||
/**
|
||||
* Base decoder for UBL-based invoice formats
|
||||
|
@ -2,8 +2,7 @@ import { BaseValidator } from '../base/base.validator.js';
|
||||
import { ValidationLevel } from '../../interfaces/common.js';
|
||||
import type { ValidationResult } from '../../interfaces/common.js';
|
||||
import { UBLDocumentType } from './ubl.types.js';
|
||||
import { DOMParser } from 'xmldom';
|
||||
import * as xpath from 'xpath';
|
||||
import { DOMParser, xpath } from '../../plugins.js';
|
||||
|
||||
/**
|
||||
* Base validator for UBL-based invoice formats
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { UBLBaseDecoder } from '../ubl.decoder.js';
|
||||
import type { TInvoice, TCreditNote, TDebitNote } from '../../../interfaces/common.js';
|
||||
import { business, finance } from '@tsclass/tsclass';
|
||||
import { business, finance } from '../../../plugins.js';
|
||||
import { UBLDocumentType } from '../ubl.types.js';
|
||||
|
||||
/**
|
||||
@ -15,14 +15,14 @@ export class XRechnungDecoder extends UBLBaseDecoder {
|
||||
protected async decodeCreditNote(): Promise<TCreditNote> {
|
||||
// Extract common data
|
||||
const commonData = await this.extractCommonData();
|
||||
|
||||
|
||||
// Return the invoice data as a credit note
|
||||
return {
|
||||
...commonData,
|
||||
invoiceType: 'creditnote'
|
||||
} as TCreditNote;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Decodes a UBL debit note (invoice)
|
||||
* @returns Promise resolving to a TDebitNote object
|
||||
@ -30,14 +30,14 @@ export class XRechnungDecoder extends UBLBaseDecoder {
|
||||
protected async decodeDebitNote(): Promise<TDebitNote> {
|
||||
// Extract common data
|
||||
const commonData = await this.extractCommonData();
|
||||
|
||||
|
||||
// Return the invoice data as a debit note
|
||||
return {
|
||||
...commonData,
|
||||
invoiceType: 'debitnote'
|
||||
} as TDebitNote;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Extracts common invoice data from XRechnung XML
|
||||
* @returns Common invoice data
|
||||
@ -49,7 +49,7 @@ export class XRechnungDecoder extends UBLBaseDecoder {
|
||||
const issueDateText = this.getText('//cbc:IssueDate', this.doc);
|
||||
const issueDate = issueDateText ? new Date(issueDateText).getTime() : Date.now();
|
||||
const currencyCode = this.getText('//cbc:DocumentCurrencyCode', this.doc) || 'EUR';
|
||||
|
||||
|
||||
// Extract payment terms
|
||||
let dueInDays = 30; // Default
|
||||
const dueDateText = this.getText('//cac:PaymentTerms/cbc:PaymentDueDate', this.doc);
|
||||
@ -59,38 +59,38 @@ export class XRechnungDecoder extends UBLBaseDecoder {
|
||||
const diffTime = Math.abs(dueDateObj.getTime() - issueDateObj.getTime());
|
||||
dueInDays = Math.ceil(diffTime / (1000 * 60 * 60 * 24));
|
||||
}
|
||||
|
||||
|
||||
// Extract items
|
||||
const items: finance.TInvoiceItem[] = [];
|
||||
const invoiceLines = this.select('//cac:InvoiceLine', this.doc);
|
||||
|
||||
|
||||
if (invoiceLines && Array.isArray(invoiceLines)) {
|
||||
for (let i = 0; i < invoiceLines.length; i++) {
|
||||
const line = invoiceLines[i];
|
||||
|
||||
|
||||
const position = i + 1;
|
||||
const name = this.getText('./cac:Item/cbc:Name', line) || `Item ${position}`;
|
||||
const articleNumber = this.getText('./cac:Item/cac:SellersItemIdentification/cbc:ID', line) || '';
|
||||
const unitType = this.getText('./cbc:InvoicedQuantity/@unitCode', line) || 'EA';
|
||||
|
||||
|
||||
let unitQuantity = 1;
|
||||
const quantityText = this.getText('./cbc:InvoicedQuantity', line);
|
||||
if (quantityText) {
|
||||
unitQuantity = parseFloat(quantityText) || 1;
|
||||
}
|
||||
|
||||
|
||||
let unitNetPrice = 0;
|
||||
const priceText = this.getText('./cac:Price/cbc:PriceAmount', line);
|
||||
if (priceText) {
|
||||
unitNetPrice = parseFloat(priceText) || 0;
|
||||
}
|
||||
|
||||
|
||||
let vatPercentage = 0;
|
||||
const percentText = this.getText('./cac:Item/cac:ClassifiedTaxCategory/cbc:Percent', line);
|
||||
if (percentText) {
|
||||
vatPercentage = parseFloat(percentText) || 0;
|
||||
}
|
||||
|
||||
|
||||
items.push({
|
||||
position,
|
||||
name,
|
||||
@ -102,7 +102,7 @@ export class XRechnungDecoder extends UBLBaseDecoder {
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Extract notes
|
||||
const notes: string[] = [];
|
||||
const noteNodes = this.select('//cbc:Note', this.doc);
|
||||
@ -114,11 +114,11 @@ export class XRechnungDecoder extends UBLBaseDecoder {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Extract seller and buyer information
|
||||
const seller = this.extractParty('//cac:AccountingSupplierParty/cac:Party');
|
||||
const buyer = this.extractParty('//cac:AccountingCustomerParty/cac:Party');
|
||||
|
||||
|
||||
// Create the common invoice data
|
||||
return {
|
||||
type: 'invoice',
|
||||
@ -169,7 +169,7 @@ export class XRechnungDecoder extends UBLBaseDecoder {
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Extracts party information from XML
|
||||
* @param partyPath XPath to the party element
|
||||
@ -188,26 +188,26 @@ export class XRechnungDecoder extends UBLBaseDecoder {
|
||||
let vatId = '';
|
||||
let registrationId = '';
|
||||
let registrationName = '';
|
||||
|
||||
|
||||
// Try to extract party information
|
||||
const partyNodes = this.select(partyPath, this.doc);
|
||||
|
||||
|
||||
if (partyNodes && Array.isArray(partyNodes) && partyNodes.length > 0) {
|
||||
const party = partyNodes[0];
|
||||
|
||||
|
||||
// Extract name
|
||||
name = this.getText('./cac:PartyName/cbc:Name', party) || '';
|
||||
|
||||
|
||||
// Extract address
|
||||
const addressNodes = this.select('./cac:PostalAddress', party);
|
||||
if (addressNodes && Array.isArray(addressNodes) && addressNodes.length > 0) {
|
||||
const address = addressNodes[0];
|
||||
|
||||
|
||||
streetName = this.getText('./cbc:StreetName', address) || '';
|
||||
houseNumber = this.getText('./cbc:BuildingNumber', address) || '0';
|
||||
city = this.getText('./cbc:CityName', address) || '';
|
||||
postalCode = this.getText('./cbc:PostalZone', address) || '';
|
||||
|
||||
|
||||
const countryNodes = this.select('./cac:Country', address);
|
||||
if (countryNodes && Array.isArray(countryNodes) && countryNodes.length > 0) {
|
||||
const countryNode = countryNodes[0];
|
||||
@ -215,13 +215,13 @@ export class XRechnungDecoder extends UBLBaseDecoder {
|
||||
countryCode = this.getText('./cbc:IdentificationCode', countryNode) || '';
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Extract tax information
|
||||
const taxSchemeNodes = this.select('./cac:PartyTaxScheme', party);
|
||||
if (taxSchemeNodes && Array.isArray(taxSchemeNodes) && taxSchemeNodes.length > 0) {
|
||||
vatId = this.getText('./cbc:CompanyID', taxSchemeNodes[0]) || '';
|
||||
}
|
||||
|
||||
|
||||
// Extract registration information
|
||||
const legalEntityNodes = this.select('./cac:PartyLegalEntity', party);
|
||||
if (legalEntityNodes && Array.isArray(legalEntityNodes) && legalEntityNodes.length > 0) {
|
||||
@ -229,7 +229,7 @@ export class XRechnungDecoder extends UBLBaseDecoder {
|
||||
registrationName = this.getText('./cbc:RegistrationName', legalEntityNodes[0]) || name;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return {
|
||||
type: 'company',
|
||||
name: name,
|
||||
@ -259,7 +259,7 @@ export class XRechnungDecoder extends UBLBaseDecoder {
|
||||
return this.createEmptyContact();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Creates an empty TContact object
|
||||
* @returns Empty TContact object
|
||||
|
@ -1,6 +1,5 @@
|
||||
import { InvoiceFormat } from '../../interfaces/common.js';
|
||||
import { DOMParser } from 'xmldom';
|
||||
import * as xpath from 'xpath';
|
||||
import { DOMParser, xpath } from '../../plugins.js';
|
||||
import { CII_PROFILE_IDS, ZUGFERD_V1_NAMESPACES } from '../cii/cii.types.js';
|
||||
|
||||
/**
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { business, finance } from '@tsclass/tsclass';
|
||||
import { business, finance } from '../plugins.js';
|
||||
|
||||
/**
|
||||
* Supported electronic invoice formats
|
||||
|
Reference in New Issue
Block a user