UNPKG

@openade/fe

Version:

Fatturazione Elettronica - Electronic Invoicing for Sistema di Interscambio (SDI)

317 lines 11.1 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.CrossBorderManager = void 0; exports.createCrossBorderManager = createCrossBorderManager; exports.validateCrossBorderInvoice = validateCrossBorderInvoice; exports.validateEUVATNumber = validateEUVATNumber; const euvat_service_1 = require("./euvat.service"); class CrossBorderManager { constructor(config = {}) { this.config = { enableEUVATValidation: true, enableCountryValidation: true, enableCurrencyValidation: true, defaultCurrency: 'EUR', euCountries: [ 'AT', 'BE', 'BG', 'HR', 'CY', 'CZ', 'DK', 'EE', 'FI', 'FR', 'DE', 'GR', 'HU', 'IE', 'IT', 'LV', 'LT', 'LU', 'MT', 'NL', 'PL', 'PT', 'RO', 'SK', 'SI', 'ES', 'SE', ], vatRates: { IT: 22, DE: 19, FR: 20, ES: 21, NL: 21, BE: 21, AT: 20, PT: 23, FI: 24, IE: 23, GR: 24, LU: 17, MT: 18, CY: 19, EE: 20, LV: 21, LT: 21, PL: 23, CZ: 21, SK: 20, HU: 27, SI: 22, HR: 25, RO: 19, BG: 20, DK: 25, SE: 25, }, ...config, }; this.euVatService = new euvat_service_1.EUVATService(); } async validateCrossBorderInvoice(invoice) { const errors = []; const warnings = []; const recommendations = []; try { const supplier = invoice.fatturaElettronicaHeader.cedentePrestatore; const customer = invoice.fatturaElettronicaHeader.cessionarioCommittente; const supplierCountry = this.extractCountry(supplier); const customerCountry = this.extractCountry(customer); if (this.config.enableCountryValidation) { const countryValidation = this.validateCountries(supplierCountry, customerCountry); errors.push(...countryValidation.errors); warnings.push(...countryValidation.warnings); } const crossBorderData = this.determineCrossBorderData(supplier, customer, supplierCountry, customerCountry); if (this.config.enableEUVATValidation && this.isEUCountry(customerCountry)) { const vatValidation = await this.validateEUVATNumber(customer); if (!vatValidation.valid) { errors.push(`Invalid EU VAT number: ${vatValidation.error}`); } else { crossBorderData.vatNumberValid = true; } } if (this.config.enableCurrencyValidation) { const currencyValidation = this.validateCurrency(invoice, crossBorderData); errors.push(...currencyValidation.errors); warnings.push(...currencyValidation.warnings); } recommendations.push(...this.generateRecommendations(crossBorderData)); return { valid: errors.length === 0, errors, warnings, crossBorderData, recommendations, }; } catch (error) { return { valid: false, errors: [error instanceof Error ? error.message : 'Unknown error'], warnings, recommendations, }; } } async validateEUVATNumber(customer) { try { const vatNumber = customer.datiAnagrafici.idFiscaleIVA?.idCodice; const countryCode = customer.datiAnagrafici.idFiscaleIVA?.idPaese; if (!vatNumber || !countryCode) { return { valid: false, validationDate: new Date().toISOString(), error: 'VAT number or country code missing', }; } return await this.euVatService.validateVATNumber(vatNumber, countryCode); } catch (error) { return { valid: false, validationDate: new Date().toISOString(), error: error instanceof Error ? error.message : 'Unknown error', }; } } getVATRate(countryCode) { return this.config.vatRates?.[countryCode] || null; } isEUCountry(countryCode) { return this.config.euCountries?.includes(countryCode) || false; } extractCountry(taxpayer) { return taxpayer.sede?.nazione || 'IT'; } validateCountries(supplierCountry, customerCountry) { const errors = []; const warnings = []; if (!supplierCountry) { errors.push('Supplier country is required'); } if (!customerCountry) { errors.push('Customer country is required'); } if (supplierCountry && customerCountry) { if (supplierCountry === customerCountry) { warnings.push('Domestic transaction detected'); } if (supplierCountry !== 'IT' && customerCountry !== 'IT') { warnings.push('Third-country transaction detected'); } } return { errors, warnings }; } determineCrossBorderData(supplier, customer, supplierCountry, customerCountry) { const hasVATNumber = !!customer.DatiAnagrafici.idFiscaleIVA?.idCodice; const isSupplierIT = supplierCountry === 'IT'; const isCustomerIT = customerCountry === 'IT'; const isCustomerEU = this.isEUCountry(customerCountry); let transactionType = 'B2C'; let vatTreatment; if (hasVATNumber) { transactionType = 'B2B'; } if (isSupplierIT && isCustomerIT) { vatTreatment = 'DOMESTIC'; } else if (isSupplierIT && isCustomerEU && hasVATNumber) { vatTreatment = 'EU_B2B'; } else if (isSupplierIT && isCustomerEU && !hasVATNumber) { vatTreatment = 'EU_B2C'; } else if (isSupplierIT && !isCustomerEU) { vatTreatment = 'EXPORT'; } else if (!isSupplierIT && isCustomerIT) { vatTreatment = 'IMPORT'; } else { vatTreatment = 'EXPORT'; } return { supplierCountry, customerCountry, transactionType, vatTreatment, currency: this.config.defaultCurrency, vatNumberValid: hasVATNumber, }; } validateCurrency(invoice, crossBorderData) { const errors = []; const warnings = []; const invoiceCurrency = this.extractCurrency(invoice); if (!invoiceCurrency) { if (crossBorderData.vatTreatment !== 'DOMESTIC') { warnings.push('Currency not specified for international transaction'); } } else { if (crossBorderData.vatTreatment === 'DOMESTIC' && invoiceCurrency !== 'EUR') { warnings.push('Non-EUR currency for domestic transaction'); } } return { errors, warnings }; } extractCurrency(invoice) { const body = Array.isArray(invoice.fatturaElettronicaBody) ? invoice.fatturaElettronicaBody[0] : invoice.fatturaElettronicaBody; if (body.datiPagamento && body.datiPagamento.length > 0) { return body.datiPagamento[0].condizioniPagamento || null; } return null; } validateVATNumberFormat(vatNumber, countryCode) { const patterns = { IT: /^IT\d{11}$/, DE: /^DE\d{9}$/, FR: /^FR[A-Z0-9]{2}\d{9}$/, ES: /^ES[A-Z0-9]\d{7}[A-Z0-9]$/, NL: /^NL\d{9}B\d{2}$/, BE: /^BE\d{10}$/, AT: /^ATU\d{8}$/, PT: /^PT\d{9}$/, FI: /^FI\d{8}$/, IE: /^IE\d[A-Z0-9+*]\d{5}[A-Z]$/, GR: /^GR\d{9}$/, LU: /^LU\d{8}$/, MT: /^MT\d{8}$/, CY: /^CY\d{8}[A-Z]$/, EE: /^EE\d{9}$/, LV: /^LV\d{11}$/, LT: /^LT(\d{9}|\d{12})$/, PL: /^PL\d{10}$/, CZ: /^CZ\d{8,10}$/, SK: /^SK\d{10}$/, HU: /^HU\d{8}$/, SI: /^SI\d{8}$/, HR: /^HR\d{11}$/, RO: /^RO\d{2,10}$/, BG: /^BG\d{9,10}$/, DK: /^DK\d{8}$/, SE: /^SE\d{12}$/, }; const pattern = patterns[countryCode]; return pattern ? pattern.test(vatNumber) : false; } formatAddress(address) { return `${address.indirizzo}, ${address.cap} ${address.comune}, ${address.nazione}`; } generateRecommendations(crossBorderData) { const recommendations = []; if (crossBorderData.vatTreatment === 'EU_B2B') { recommendations.push('Consider using reverse charge mechanism for EU B2B transactions'); } if (crossBorderData.vatTreatment === 'EXPORT') { recommendations.push('Verify export documentation requirements'); } if (crossBorderData.vatTreatment === 'IMPORT') { recommendations.push('Check import VAT obligations'); } if (crossBorderData.currency !== 'EUR') { recommendations.push('Consider currency exchange rate documentation'); } return recommendations; } } exports.CrossBorderManager = CrossBorderManager; function createCrossBorderManager(config = {}) { return new CrossBorderManager(config); } async function validateCrossBorderInvoice(invoice, config = {}) { const manager = createCrossBorderManager(config); return await manager.validateCrossBorderInvoice(invoice); } async function validateEUVATNumber(vatNumber, countryCode, config = {}) { const manager = createCrossBorderManager(config); const customer = { DatiAnagrafici: { idFiscaleIVA: { idPaese: countryCode, idCodice: vatNumber, }, anagrafica: { denominazione: 'Unknown', }, }, sede: { indirizzo: 'Unknown', cap: '00000', comune: 'Unknown', nazione: countryCode, }, }; return await manager.validateEUVATNumber(customer); } //# sourceMappingURL=crossborder.manager.js.map