feat(compliance): improve compliance

This commit is contained in:
2025-05-26 13:33:21 +00:00
parent e7c3a774a3
commit 26deb14893
13 changed files with 3520 additions and 2818 deletions

View File

@ -70,7 +70,11 @@ export class XRechnungDecoder extends UBLBaseDecoder {
const position = i + 1;
const name = this.getText('./cac:Item/cbc:Name', line) || `Item ${position}`;
const description = this.getText('./cac:Item/cbc:Description', line) || '';
const articleNumber = this.getText('./cac:Item/cac:SellersItemIdentification/cbc:ID', line) || '';
const buyerItemID = this.getText('./cac:Item/cac:BuyersItemIdentification/cbc:ID', line) || '';
const standardItemID = this.getText('./cac:Item/cac:StandardItemIdentification/cbc:ID', line) || '';
const commodityClassification = this.getText('./cac:Item/cac:CommodityClassification/cbc:ItemClassificationCode', line) || '';
const unitType = this.getText('./cbc:InvoicedQuantity/@unitCode', line) || 'EA';
let unitQuantity = 1;
@ -91,7 +95,8 @@ export class XRechnungDecoder extends UBLBaseDecoder {
vatPercentage = parseFloat(percentText) || 0;
}
items.push({
// Create item with extended metadata
const item: finance.TAccountingDocItem & { metadata?: any } = {
position,
name,
articleNumber,
@ -99,10 +104,57 @@ export class XRechnungDecoder extends UBLBaseDecoder {
unitQuantity,
unitNetPrice,
vatPercentage
});
};
// Extract additional item properties
const additionalProps: Record<string, string> = {};
const propNodes = this.select('./cac:Item/cac:AdditionalItemProperty', line);
if (propNodes && Array.isArray(propNodes)) {
for (const propNode of propNodes) {
const propName = this.getText('./cbc:Name', propNode);
const propValue = this.getText('./cbc:Value', propNode);
if (propName && propValue) {
additionalProps[propName] = propValue;
}
}
}
// Store additional item data in metadata
if (description || buyerItemID || standardItemID || commodityClassification || Object.keys(additionalProps).length > 0) {
item.metadata = {
description,
buyerItemID,
standardItemID,
commodityClassification,
additionalProperties: additionalProps
};
}
items.push(item);
}
}
// Extract business references
const orderReference = this.getText('//cac:OrderReference/cbc:ID', this.doc);
const contractReference = this.getText('//cac:ContractDocumentReference/cbc:ID', this.doc);
const projectReference = this.getText('//cac:ProjectReference/cbc:ID', this.doc);
// Extract payment information
const paymentMeansCode = this.getText('//cac:PaymentMeans/cbc:PaymentMeansCode', this.doc);
const paymentID = this.getText('//cac:PaymentMeans/cbc:PaymentID', this.doc);
const iban = this.getText('//cac:PaymentMeans/cac:PayeeFinancialAccount/cbc:ID', this.doc);
const bic = this.getText('//cac:PaymentMeans/cac:PayeeFinancialAccount/cac:FinancialInstitutionBranch/cac:FinancialInstitution/cbc:ID', this.doc);
const accountName = this.getText('//cac:PaymentMeans/cac:PayeeFinancialAccount/cbc:Name', this.doc);
// Extract payment terms with discount
const paymentTermsNote = this.getText('//cac:PaymentTerms/cbc:Note', this.doc);
const discountPercent = this.getText('//cac:PaymentTerms/cbc:SettlementDiscountPercent', this.doc);
// Extract period information
const periodStart = this.getText('//cac:InvoicePeriod/cbc:StartDate', this.doc);
const periodEnd = this.getText('//cac:InvoicePeriod/cbc:EndDate', this.doc);
const deliveryDate = this.getText('//cac:Delivery/cbc:ActualDeliveryDate', this.doc);
// Extract notes
const notes: string[] = [];
const noteNodes = this.select('//cbc:Note', this.doc);
@ -119,8 +171,8 @@ export class XRechnungDecoder extends UBLBaseDecoder {
const seller = this.extractParty('//cac:AccountingSupplierParty/cac:Party');
const buyer = this.extractParty('//cac:AccountingCustomerParty/cac:Party');
// Create the common invoice data
return {
// Create the common invoice data with metadata for business references
const invoiceData: any = {
type: 'accounting-doc' as const,
accountingDocType: 'invoice' as const,
id: invoiceId,
@ -141,8 +193,35 @@ export class XRechnungDecoder extends UBLBaseDecoder {
reverseCharge: false,
currency: currencyCode as finance.TCurrency,
notes: notes,
objectActions: []
objectActions: [],
metadata: {
format: 'xrechnung' as any,
version: '1.0.0',
extensions: {
businessReferences: {
orderReference,
contractReference,
projectReference
},
paymentInformation: {
paymentMeansCode,
paymentID,
iban,
bic,
accountName,
paymentTermsNote,
discountPercent
},
dateInformation: {
periodStart,
periodEnd,
deliveryDate
}
}
}
};
return invoiceData;
} catch (error) {
console.error('Error extracting common data:', error);
// Return default data
@ -190,6 +269,9 @@ export class XRechnungDecoder extends UBLBaseDecoder {
let vatId = '';
let registrationId = '';
let registrationName = '';
let contactPhone = '';
let contactEmail = '';
let contactName = '';
// Try to extract party information
const partyNodes = this.select(partyPath, this.doc);
@ -230,9 +312,19 @@ export class XRechnungDecoder extends UBLBaseDecoder {
registrationId = this.getText('./cbc:CompanyID', legalEntityNodes[0]) || '';
registrationName = this.getText('./cbc:RegistrationName', legalEntityNodes[0]) || name;
}
// Extract contact information
const contactNodes = this.select('./cac:Contact', party);
if (contactNodes && Array.isArray(contactNodes) && contactNodes.length > 0) {
const contact = contactNodes[0];
contactPhone = this.getText('./cbc:Telephone', contact) || '';
contactEmail = this.getText('./cbc:ElectronicMail', contact) || '';
contactName = this.getText('./cbc:Name', contact) || '';
}
}
return {
// Create contact with additional metadata for contact information
const contact: business.TContact & { metadata?: any } = {
type: 'company',
name: name,
description: '',
@ -256,6 +348,19 @@ export class XRechnungDecoder extends UBLBaseDecoder {
registrationName: registrationName
}
};
// Store contact information in metadata if available
if (contactPhone || contactEmail || contactName) {
contact.metadata = {
contactInformation: {
phone: contactPhone,
email: contactEmail,
name: contactName
}
};
}
return contact;
} catch (error) {
console.error('Error extracting party information:', error);
return this.createEmptyContact();