import { UBLBaseEncoder } from '../ubl.encoder.js'; import type { TInvoice, TCreditNote, TDebitNote } from '../../../interfaces/common.js'; import { UBLDocumentType } from '../ubl.types.js'; /** * Encoder for XRechnung (UBL) format * Implements encoding of TInvoice to XRechnung XML */ export class XRechnungEncoder extends UBLBaseEncoder { /** * Encodes a TCreditNote object to XRechnung XML * @param creditNote TCreditNote object to encode * @returns Promise resolving to XML string */ protected async encodeCreditNote(creditNote: TCreditNote): Promise<string> { // For now, we'll just return a simple UBL credit note template // In a real implementation, we would generate a proper UBL credit note return `<?xml version="1.0" encoding="UTF-8"?> <CreditNote xmlns="urn:oasis:names:specification:ubl:schema:xsd:CreditNote-2" xmlns:cac="urn:oasis:names:specification:ubl:schema:xsd:CommonAggregateComponents-2" xmlns:cbc="urn:oasis:names:specification:ubl:schema:xsd:CommonBasicComponents-2"> <cbc:CustomizationID>urn:cen.eu:en16931:2017#compliant#urn:xoev-de:kosit:standard:xrechnung_2.0</cbc:CustomizationID> <cbc:ID>${creditNote.id}</cbc:ID> <cbc:IssueDate>${this.formatDate(creditNote.date)}</cbc:IssueDate> <cbc:CreditNoteTypeCode>381</cbc:CreditNoteTypeCode> <cbc:DocumentCurrencyCode>${creditNote.currency}</cbc:DocumentCurrencyCode> <!-- Rest of the credit note XML would go here --> </CreditNote>`; } /** * Encodes a TDebitNote object to XRechnung XML * @param debitNote TDebitNote object to encode * @returns Promise resolving to XML string */ protected async encodeDebitNote(debitNote: TDebitNote): Promise<string> { // For now, we'll just return a simple UBL invoice template // In a real implementation, we would generate a proper UBL invoice return `<?xml version="1.0" encoding="UTF-8"?> <Invoice xmlns="urn:oasis:names:specification:ubl:schema:xsd:Invoice-2" xmlns:cac="urn:oasis:names:specification:ubl:schema:xsd:CommonAggregateComponents-2" xmlns:cbc="urn:oasis:names:specification:ubl:schema:xsd:CommonBasicComponents-2"> <cbc:CustomizationID>urn:cen.eu:en16931:2017#compliant#urn:xoev-de:kosit:standard:xrechnung_2.0</cbc:CustomizationID> <cbc:ID>${debitNote.id}</cbc:ID> <cbc:IssueDate>${this.formatDate(debitNote.date)}</cbc:IssueDate> <cbc:DueDate>${this.formatDate(debitNote.date + debitNote.dueInDays * 24 * 60 * 60 * 1000)}</cbc:DueDate> <cbc:InvoiceTypeCode>380</cbc:InvoiceTypeCode> <cbc:DocumentCurrencyCode>${debitNote.currency}</cbc:DocumentCurrencyCode> <cac:AccountingSupplierParty> <cac:Party> <cac:PartyName> <cbc:Name>${debitNote.from.name}</cbc:Name> </cac:PartyName> <cac:PostalAddress> <cbc:StreetName>${debitNote.from.address.streetName || ''}</cbc:StreetName> <cbc:BuildingNumber>${debitNote.from.address.houseNumber || ''}</cbc:BuildingNumber> <cbc:CityName>${debitNote.from.address.city || ''}</cbc:CityName> <cbc:PostalZone>${debitNote.from.address.postalCode || ''}</cbc:PostalZone> <cac:Country> <cbc:IdentificationCode>${debitNote.from.address.countryCode || ''}</cbc:IdentificationCode> </cac:Country> </cac:PostalAddress> ${debitNote.from.registrationDetails?.vatId ? ` <cac:PartyTaxScheme> <cbc:CompanyID>${debitNote.from.registrationDetails.vatId}</cbc:CompanyID> <cac:TaxScheme> <cbc:ID>VAT</cbc:ID> </cac:TaxScheme> </cac:PartyTaxScheme>` : ''} ${debitNote.from.registrationDetails?.registrationId ? ` <cac:PartyLegalEntity> <cbc:RegistrationName>${debitNote.from.registrationDetails.registrationName || debitNote.from.name}</cbc:RegistrationName> <cbc:CompanyID>${debitNote.from.registrationDetails.registrationId}</cbc:CompanyID> </cac:PartyLegalEntity>` : ''} </cac:Party> </cac:AccountingSupplierParty> <cac:AccountingCustomerParty> <cac:Party> <cac:PartyName> <cbc:Name>${debitNote.to.name}</cbc:Name> </cac:PartyName> <cac:PostalAddress> <cbc:StreetName>${debitNote.to.address.streetName || ''}</cbc:StreetName> <cbc:BuildingNumber>${debitNote.to.address.houseNumber || ''}</cbc:BuildingNumber> <cbc:CityName>${debitNote.to.address.city || ''}</cbc:CityName> <cbc:PostalZone>${debitNote.to.address.postalCode || ''}</cbc:PostalZone> <cac:Country> <cbc:IdentificationCode>${debitNote.to.address.countryCode || ''}</cbc:IdentificationCode> </cac:Country> </cac:PostalAddress> ${debitNote.to.registrationDetails?.vatId ? ` <cac:PartyTaxScheme> <cbc:CompanyID>${debitNote.to.registrationDetails.vatId}</cbc:CompanyID> <cac:TaxScheme> <cbc:ID>VAT</cbc:ID> </cac:TaxScheme> </cac:PartyTaxScheme>` : ''} </cac:Party> </cac:AccountingCustomerParty> <cac:PaymentTerms> <cbc:Note>Due in ${debitNote.dueInDays} days</cbc:Note> </cac:PaymentTerms> <cac:TaxTotal> <cbc:TaxAmount currencyID="${debitNote.currency}">0.00</cbc:TaxAmount> </cac:TaxTotal> <cac:LegalMonetaryTotal> <cbc:LineExtensionAmount currencyID="${debitNote.currency}">0.00</cbc:LineExtensionAmount> <cbc:TaxExclusiveAmount currencyID="${debitNote.currency}">0.00</cbc:TaxExclusiveAmount> <cbc:TaxInclusiveAmount currencyID="${debitNote.currency}">0.00</cbc:TaxInclusiveAmount> <cbc:PayableAmount currencyID="${debitNote.currency}">0.00</cbc:PayableAmount> </cac:LegalMonetaryTotal> ${debitNote.items.map((item, index) => ` <cac:InvoiceLine> <cbc:ID>${index + 1}</cbc:ID> <cbc:InvoicedQuantity unitCode="${item.unitType}">${item.unitQuantity}</cbc:InvoicedQuantity> <cbc:LineExtensionAmount currencyID="${debitNote.currency}">${item.unitNetPrice * item.unitQuantity}</cbc:LineExtensionAmount> <cac:Item> <cbc:Name>${item.name}</cbc:Name> ${item.articleNumber ? ` <cac:SellersItemIdentification> <cbc:ID>${item.articleNumber}</cbc:ID> </cac:SellersItemIdentification>` : ''} <cac:ClassifiedTaxCategory> <cbc:ID>S</cbc:ID> <cbc:Percent>${item.vatPercentage}</cbc:Percent> <cac:TaxScheme> <cbc:ID>VAT</cbc:ID> </cac:TaxScheme> </cac:ClassifiedTaxCategory> </cac:Item> <cac:Price> <cbc:PriceAmount currencyID="${debitNote.currency}">${item.unitNetPrice}</cbc:PriceAmount> </cac:Price> </cac:InvoiceLine>`).join('')} </Invoice>`; } }