Files
accounted/extensions/export/intrastat/lib/scb-csv-generator.ts
T
EmilandClaude Opus 4.6 0764bc11a6 feat: implement 4 export extensions with engines, API routes, and workspaces
- EU Sales List: engine, CSV/XML generators, Skatteverket format, tests
- VAT Monitor: moms box mapping, revenue breakdown, validation, tests
- Intrastat: product registry, SCB CSV generator, threshold tracking, tests
- Currency Receivables: FX exposure, unrealized gain/loss calc, tests
- Shared utilities: EU country list, moms box mapping
- API routes for report generation and file downloads
- Workspace UI components for all 4 extensions

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-24 14:10:16 +01:00

75 lines
2.1 KiB
TypeScript

/**
* Intrastat SCB CSV Generator
*
* Generates a semicolon-separated CSV file (UTF-8 with BOM)
* compatible with SCB's IDEP.web upload for Intrastat declarations.
*
* Format: Semicolon-delimited, UTF-8 BOM, whole SEK amounts,
* net mass in kg with up to 3 decimal places.
*
* Reference: SCB IDEP.web filformat, Intrastat utförsel
*/
import type { IntrastatReport } from './intrastat-engine'
const UTF8_BOM = '\uFEFF'
/**
* Generate an IDEP.web-compatible CSV for the Intrastat report.
*
* Columns (matching SCB IDEP.web format):
* CN-kod;Partnerland;Ursprungsland;Transaktionstyp;Leveransvillkor;
* Fakturerat värde (SEK);Nettovikt (kg);Kompletterande enhet;Partner-VAT
*/
export function generateSCBCsv(report: IntrastatReport): string {
const header = [
'CN-kod',
'Partnerland',
'Ursprungsland',
'Transaktionstyp',
'Leveransvillkor',
'Fakturerat värde (SEK)',
'Nettovikt (kg)',
'Kompletterande enhet',
'Partner-VAT',
].join(';')
const rows = report.lines.map(line => {
const value = Math.round(line.invoicedValue)
const mass = roundMass(line.netMass)
const suppUnit = line.supplementaryUnit !== null ? String(Math.round(line.supplementaryUnit)) : ''
return [
line.cnCode,
line.partnerCountry,
line.countryOfOrigin,
line.transactionNature,
line.deliveryTerms,
String(value),
String(mass),
suppUnit,
line.partnerVatId,
].join(';')
})
return UTF8_BOM + [header, ...rows].join('\r\n') + '\r\n'
}
/**
* Generate a filename for the IDEP.web CSV download.
*
* Format: INTRASTAT_<VAT>_<YYYY>-<MM>.csv
*/
export function generateSCBFilename(report: IntrastatReport): string {
const vat = report.reporterVatNumber.replace(/\s/g, '')
const period = `${report.period.year}-${String(report.period.month).padStart(2, '0')}`
return `INTRASTAT_${vat}_${period}.csv`
}
/** Round mass to max 3 decimal places, removing trailing zeros */
function roundMass(kg: number): string {
const rounded = Math.round(kg * 1000) / 1000
if (rounded === Math.floor(rounded)) return String(rounded)
return rounded.toFixed(3).replace(/0+$/, '')
}