Documentazione tecnica

@sepalo/core

Libreria TypeScript per generare, validare e parsare file XML CBIBdyPaymentRequest.00.04.01. Funziona in browser (ESM), Node.js 18+ e Deno. Zero dipendenze runtime.

Installazione

npm install @sepalo/core
# oppure
pnpm add @sepalo/core
# oppure
yarn add @sepalo/core

La validazione XSD usa xmllint-wasm come peer dependency facoltativa. Installala se vuoi la validazione lato Node:

npm install xmllint-wasm

Tipi principali

import type {
  PaymentBatch,    // intero batch: ordinante + lista transazioni
  Transaction,     // singola transazione
  Initiator,       // profilo ordinante (banca + CUC + IBAN)
  ParsedSheet,     // risultato del parsing CSV/XLSX
  ValidationResult // errori + warning di validazione
} from '@sepalo/core';
TipoDescrizione
PaymentBatchBatch completo: ordinante + array di transazioni + metadati
TransactionSingola transazione: IBAN, importo, causale, beneficiario, data
InitiatorProfilo ordinante: IBAN, ABI, CUC, nome, indirizzo
ParsedSheetOutput del parser: headers rilevati + righe normalizzate
ValidationResultArray di errors e warnings con path e codice

parseFile()

Legge un File (browser) o un Buffer (Node) CSV o XLSX e restituisce un ParsedSheet.

import { parseFile } from '@sepalo/core';

// Browser
const sheet = await parseFile(inputElement.files[0]);

// Node.js
import { readFileSync } from 'fs';
const buffer = readFileSync('bonifici.csv');
const sheet = await parseFile(new Blob([buffer]));

// sheet.headers  → string[]         (nomi colonne rilevate)
// sheet.rows     → Record<string, string>[]  (righe normalizzate)

buildXml()

Genera la stringa XML dal batch. Non effettua validazione — chiama validateBatch() prima se vuoi intercettare errori.

import { buildXml } from '@sepalo/core';
import type { PaymentBatch } from '@sepalo/core';

const batch: PaymentBatch = {
  initiator: {
    name: 'Acme S.r.l.',
    iban: 'IT60X0542811101000000123456',
    abi: '05428',
    cuc: 'ABC123',
  },
  transactions: [
    {
      id: 'txn-001',
      creditor: { name: 'Mario Rossi', iban: 'IT60X0542811101000000654321' },
      amount: 1500.0,
      currency: 'EUR',
      description: 'Fattura 2026/001',
      executionDate: '2026-06-01',
    },
  ],
  batchBooking: true,
  requestedExecutionDate: '2026-06-01',
};

const xml: string = buildXml(batch);

validateBatch()

Valida un PaymentBatch semanticamente (IBAN checksum, importi, causali). Restituisce ValidationResult.

import { validateBatch } from '@sepalo/core';

const result = validateBatch(batch);

if (result.errors.length > 0) {
  console.error('Errori di validazione:', result.errors);
  // ogni errore ha: { path, code, message }
}

if (result.warnings.length > 0) {
  console.warn('Warning:', result.warnings);
}

// procedi solo se non ci sono errori
if (result.errors.length === 0) {
  const xml = buildXml(batch);
}

validateXml()

Valida una stringa XML contro lo schema XSD ufficiale CBI. Richiede xmllint-wasm come peer dependency.

import { validateXml } from '@sepalo/core';

const { valid, errors } = await validateXml(xml);

if (!valid) {
  console.error('XML non valido:', errors);
}

Esempio completo (browser)

import { parseFile, validateBatch, buildXml, validateXml } from '@sepalo/core';
import type { PaymentBatch, Initiator } from '@sepalo/core';

const initiator: Initiator = {
  name: 'Acme S.r.l.',
  iban: 'IT60X0542811101000000123456',
  abi: '05428',
  cuc: 'ABC123',
};

async function generateXml(file: File): Promise<string> {
  // 1. Parsa il file
  const sheet = await parseFile(file);

  // 2. Mappa le righe in transazioni
  const transactions = sheet.rows.map((row, i) => ({
    id: `txn-${String(i + 1).padStart(3, '0')}`,
    creditor: { name: row.name, iban: row.iban },
    amount: parseFloat(row.amount),
    currency: 'EUR' as const,
    description: row.description,
    executionDate: row.date ?? new Date().toISOString().slice(0, 10),
  }));

  const batch: PaymentBatch = {
    initiator,
    transactions,
    batchBooking: true,
    requestedExecutionDate: transactions[0]?.executionDate ?? '',
  };

  // 3. Valida semanticamente
  const { errors } = validateBatch(batch);
  if (errors.length > 0) throw new Error(errors[0].message);

  // 4. Genera XML
  const xml = buildXml(batch);

  // 5. Valida XSD (opzionale ma consigliato)
  const { valid } = await validateXml(xml);
  if (!valid) throw new Error('XML non supera la validazione XSD');

  return xml;
}

Integrazione Node.js

// node-generate.mjs
import { readFileSync, writeFileSync } from 'fs';
import { parseFile, validateBatch, buildXml } from '@sepalo/core';

const buffer = readFileSync('bonifici.csv');
const sheet = await parseFile(new Blob([buffer]));

const batch = {
  initiator: { /* ... */ },
  transactions: sheet.rows.map(/* ... */),
  batchBooking: true,
  requestedExecutionDate: '2026-06-01',
};

const { errors } = validateBatch(batch);
if (errors.length) process.exit(1);

const xml = buildXml(batch);
writeFileSync('output.xml', xml, 'utf-8');
console.log('Generato output.xml');

Compatibile con Node.js 18+ (ESM). Per CommonJS usa import() dinamico o un bundler.

Vuoi contribuire?

Issues, PR e discussioni sono benvenute su GitHub.