feat(compliance): improve compliance

This commit is contained in:
2025-05-26 14:49:34 +00:00
parent 26deb14893
commit 206bef0619
3 changed files with 284 additions and 61 deletions

View File

@ -106,6 +106,10 @@ export class XRechnungDecoder extends UBLBaseDecoder {
vatPercentage
};
// Extract order line reference
const orderLineReference = this.getText('./cac:OrderLineReference/cac:OrderReference/cbc:ID', line) || '';
const orderLineReferenceId = this.getText('./cac:OrderLineReference/cbc:LineID', line) || '';
// Extract additional item properties
const additionalProps: Record<string, string> = {};
const propNodes = this.select('./cac:Item/cac:AdditionalItemProperty', line);
@ -120,12 +124,14 @@ export class XRechnungDecoder extends UBLBaseDecoder {
}
// Store additional item data in metadata
if (description || buyerItemID || standardItemID || commodityClassification || Object.keys(additionalProps).length > 0) {
if (description || buyerItemID || standardItemID || commodityClassification || orderLineReference || Object.keys(additionalProps).length > 0) {
item.metadata = {
description,
buyerItemID,
standardItemID,
commodityClassification,
orderLineReference,
orderLineReferenceId,
additionalProperties: additionalProps
};
}
@ -142,8 +148,10 @@ export class XRechnungDecoder extends UBLBaseDecoder {
// Extract payment information
const paymentMeansCode = this.getText('//cac:PaymentMeans/cbc:PaymentMeansCode', this.doc);
const paymentID = this.getText('//cac:PaymentMeans/cbc:PaymentID', this.doc);
const paymentDueDate = this.getText('//cac:PaymentMeans/cbc:PaymentDueDate', 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 bic = this.getText('//cac:PaymentMeans/cac:PayeeFinancialAccount/cac:FinancialInstitutionBranch/cbc:ID', this.doc);
const bankName = this.getText('//cac:PaymentMeans/cac:PayeeFinancialAccount/cac:FinancialInstitutionBranch/cbc:Name', this.doc);
const accountName = this.getText('//cac:PaymentMeans/cac:PayeeFinancialAccount/cbc:Name', this.doc);
// Extract payment terms with discount
@ -206,8 +214,10 @@ export class XRechnungDecoder extends UBLBaseDecoder {
paymentInformation: {
paymentMeansCode,
paymentID,
paymentDueDate,
iban,
bic,
bankName,
accountName,
paymentTermsNote,
discountPercent
@ -272,6 +282,8 @@ export class XRechnungDecoder extends UBLBaseDecoder {
let contactPhone = '';
let contactEmail = '';
let contactName = '';
let gln = '';
const additionalIdentifiers: any[] = [];
// Try to extract party information
const partyNodes = this.select(partyPath, this.doc);
@ -279,6 +291,28 @@ export class XRechnungDecoder extends UBLBaseDecoder {
if (partyNodes && Array.isArray(partyNodes) && partyNodes.length > 0) {
const party = partyNodes[0];
// Extract GLN from EndpointID
const endpointId = this.getText('./cbc:EndpointID[@schemeID="0088"]', party);
if (endpointId) {
gln = endpointId;
}
// Extract additional party identifications
const partyIdNodes = this.select('./cac:PartyIdentification', party);
if (partyIdNodes && Array.isArray(partyIdNodes)) {
for (const idNode of partyIdNodes) {
const idValue = this.getText('./cbc:ID', idNode);
const idElement = (idNode as Element).getElementsByTagName('cbc:ID')[0];
const schemeId = idElement?.getAttribute('schemeID');
if (idValue) {
additionalIdentifiers.push({
value: idValue,
scheme: schemeId || ''
});
}
}
}
// Extract name
name = this.getText('./cac:PartyName/cbc:Name', party) || '';
@ -349,16 +383,28 @@ export class XRechnungDecoder extends UBLBaseDecoder {
}
};
// Store contact information in metadata if available
// Store contact information and additional identifiers in metadata if available
const metadata: any = {};
if (contactPhone || contactEmail || contactName) {
contact.metadata = {
contactInformation: {
phone: contactPhone,
email: contactEmail,
name: contactName
}
metadata.contactInformation = {
phone: contactPhone,
email: contactEmail,
name: contactName
};
}
if (gln) {
(contact as any).gln = gln;
}
if (additionalIdentifiers.length > 0) {
(contact as any).additionalIdentifiers = additionalIdentifiers;
}
if (Object.keys(metadata).length > 0) {
contact.metadata = metadata;
}
return contact;
} catch (error) {

View File

@ -143,6 +143,72 @@ export class XRechnungEncoder extends UBLEncoder {
partyElement.appendChild(endpointNode);
}
}
// Add GLN (Global Location Number) if available
if (party.gln && !existingEndpoint) {
const endpointNode = doc.createElement('cbc:EndpointID');
endpointNode.setAttribute('schemeID', '0088'); // GLN scheme ID
endpointNode.textContent = party.gln;
// Insert as first child of party element
if (partyElement.firstChild) {
partyElement.insertBefore(endpointNode, partyElement.firstChild);
} else {
partyElement.appendChild(endpointNode);
}
}
// Add PartyIdentification for additional identifiers
if (party.additionalIdentifiers) {
for (const identifier of party.additionalIdentifiers) {
const partyId = doc.createElement('cac:PartyIdentification');
const id = doc.createElement('cbc:ID');
if (identifier.scheme) {
id.setAttribute('schemeID', identifier.scheme);
}
id.textContent = identifier.value;
partyId.appendChild(id);
// Insert after EndpointID or at beginning
const endpoint = partyElement.getElementsByTagName('cbc:EndpointID')[0];
if (endpoint && endpoint.nextSibling) {
partyElement.insertBefore(partyId, endpoint.nextSibling);
} else if (partyElement.firstChild) {
partyElement.insertBefore(partyId, partyElement.firstChild);
} else {
partyElement.appendChild(partyId);
}
}
}
// Add company registration number to PartyLegalEntity
if (party.registrationDetails?.registrationId) {
let legalEntity = partyElement.getElementsByTagName('cac:PartyLegalEntity')[0];
if (!legalEntity) {
legalEntity = doc.createElement('cac:PartyLegalEntity');
// Insert after PostalAddress
const postalAddress = partyElement.getElementsByTagName('cac:PostalAddress')[0];
if (postalAddress && postalAddress.nextSibling) {
partyElement.insertBefore(legalEntity, postalAddress.nextSibling);
} else {
partyElement.appendChild(legalEntity);
}
}
// Add registration name if not present
if (!legalEntity.getElementsByTagName('cbc:RegistrationName')[0]) {
const regName = doc.createElement('cbc:RegistrationName');
regName.textContent = party.registrationDetails.registrationName || party.name;
legalEntity.appendChild(regName);
}
// Add company ID if not present
if (!legalEntity.getElementsByTagName('cbc:CompanyID')[0]) {
const companyId = doc.createElement('cbc:CompanyID');
companyId.textContent = party.registrationDetails.registrationId;
legalEntity.appendChild(companyId);
}
}
}
/**
@ -256,6 +322,13 @@ export class XRechnungEncoder extends UBLEncoder {
paymentMeans.appendChild(paymentId);
}
// Add PaymentDueDate
if (paymentInfo.paymentDueDate && !paymentMeans.getElementsByTagName('cbc:PaymentDueDate')[0]) {
const dueDate = doc.createElement('cbc:PaymentDueDate');
dueDate.textContent = paymentInfo.paymentDueDate;
paymentMeans.appendChild(dueDate);
}
// Add IBAN and BIC
if (paymentInfo.iban || paymentInfo.bic) {
let payeeAccount = paymentMeans.getElementsByTagName('cac:PayeeFinancialAccount')[0];
@ -271,37 +344,42 @@ export class XRechnungEncoder extends UBLEncoder {
payeeAccount.appendChild(iban);
}
// Add BIC
if (paymentInfo.bic) {
// Add account name (must come after ID but before FinancialInstitutionBranch)
if (paymentInfo.accountName && !payeeAccount.getElementsByTagName('cbc:Name')[0]) {
const accountName = doc.createElement('cbc:Name');
accountName.textContent = paymentInfo.accountName;
// Insert after ID but before FinancialInstitutionBranch
const id = payeeAccount.getElementsByTagName('cbc:ID')[0];
const finInstBranch = payeeAccount.getElementsByTagName('cac:FinancialInstitutionBranch')[0];
if (finInstBranch) {
payeeAccount.insertBefore(accountName, finInstBranch);
} else if (id && id.nextSibling) {
payeeAccount.insertBefore(accountName, id.nextSibling);
} else {
payeeAccount.appendChild(accountName);
}
}
// Add BIC and bank name
if (paymentInfo.bic || paymentInfo.bankName) {
let finInstBranch = payeeAccount.getElementsByTagName('cac:FinancialInstitutionBranch')[0];
if (!finInstBranch) {
finInstBranch = doc.createElement('cac:FinancialInstitutionBranch');
payeeAccount.appendChild(finInstBranch);
}
let finInst = finInstBranch.getElementsByTagName('cac:FinancialInstitution')[0];
if (!finInst) {
finInst = doc.createElement('cac:FinancialInstitution');
finInstBranch.appendChild(finInst);
// Add BIC as branch ID
if (paymentInfo.bic && !finInstBranch.getElementsByTagName('cbc:ID')[0]) {
const bicElement = doc.createElement('cbc:ID');
bicElement.textContent = paymentInfo.bic;
finInstBranch.appendChild(bicElement);
}
if (!finInst.getElementsByTagName('cbc:ID')[0]) {
const bic = doc.createElement('cbc:ID');
bic.textContent = paymentInfo.bic;
finInst.appendChild(bic);
}
}
// Add account name
if (paymentInfo.accountName && !payeeAccount.getElementsByTagName('cbc:Name')[0]) {
const accountName = doc.createElement('cbc:Name');
accountName.textContent = paymentInfo.accountName;
// Insert after ID
const id = payeeAccount.getElementsByTagName('cbc:ID')[0];
if (id && id.nextSibling) {
payeeAccount.insertBefore(accountName, id.nextSibling);
} else {
payeeAccount.appendChild(accountName);
// Add bank name
if (paymentInfo.bankName && !finInstBranch.getElementsByTagName('cbc:Name')[0]) {
const bankNameElement = doc.createElement('cbc:Name');
bankNameElement.textContent = paymentInfo.bankName;
finInstBranch.appendChild(bankNameElement);
}
}
}