aziendasanitaria-utils
v1.2.76
Published
Un utility per gestire i flussi sanitari Siciliani e non solo..
Maintainers
Readme
aziendasanitaria-utils
Libreria Node.js per la gestione dei flussi informativi sanitari della Regione Sicilia e l'integrazione con i portali istituzionali (Tessera Sanitaria, NAR/NAR2).
Indice
- Installazione
- Quick Start
- Architettura
- Moduli
- API Reference
- Struttura del Progetto
- Dipendenze Principali
- Licenza
Installazione
npm install aziendasanitaria-utilsRequisiti: Node.js >= 14.0.0 | ES Modules (
"type": "module")
Quick Start
import { flussiRegioneSicilia } from "aziendasanitaria-utils";
import { struttureDistrettiMap, distretti, comuniDistretti } from "aziendasanitaria-utils/src/config/sicilia/messina.js";
// Configurazione strutture territoriali
const strutture = new flussiRegioneSicilia.StruttureDistrettiPerProvincia(
distretti, comuniDistretti, struttureDistrettiMap
);
// Impostazioni Flusso M
const impostazioni = new flussiRegioneSicilia.ImpostazioniFlussoM(
"205", // codice ASL
"190", // codice Regione
"/path/to/input", // cartella input
"/path/to/output", // cartella output
"/path/to/FlowLook.mdb", // database FlowLook
strutture
);
// Elaborazione
const flussoM = new flussiRegioneSicilia.FlussoM(impostazioni);Architettura
aziendasanitaria-utils
|
|-- Flussi Sanitari Elaborazione file a record fisso (TXT 381 char)
| |-- FlussoM Prestazioni specialistiche ambulatoriali
| |-- FlussoSIAD Sistema Informativo Assistenza Domiciliare
| |-- FlussoHOSPICE Cure palliative
| |-- FlussoARSFAR Assistenza Residenziale Semiresidenziale
| `-- FlussoRSA Residenze Sanitarie Assistenziali
|
|-- Servizi Esterni Integrazione con portali istituzionali
| |-- Ts Tessera Sanitaria (HTTP headless + Puppeteer)
| |-- Nar / Nar2 Nuova Anagrafe Regionale (Puppeteer + REST API)
| |-- Assistiti Gestione completa dati assistiti
| `-- Medici Gestione dati medici MMG/PLS
|
|-- Indicatori Calcolo indicatori LEA (D33ZA, D30Z)
|
`-- Config Configurazione territoriale e credenzialiModuli
Flussi Sanitari
FlussoM - Prestazioni Specialistiche
Il modulo principale per l'elaborazione del flusso M (prestazioni ambulatoriali).
| Funzionalita | Stato | |---|:---:| | Verifica formale record | ✅ | | Acquisizione dati da DB FlowLook | ✅ | | Unione file TXT | ✅ | | Verifica duplicati (anche milioni di record) | ✅ | | Controllo date, nomi file, distretti | ✅ | | Elaborazione informazioni finanziarie | ✅ | | Verifica strutture su portale Sogei/TS | ✅ | | Calcolo differenze e congruita TS | ✅ | | Report HTML ed Excel | ✅ | | Invio report via mail per distretto | ✅ | | Calcolo volumi | ✅ |
FlussoSIAD - Assistenza Domiciliare
| Funzionalita | Stato | |---|:---:| | Conteggio prestazioni | ✅ |
FlussoHOSPICE - Cure Palliative
| Funzionalita | Stato | |---|:---:| | Calcolo giornate di degenza | ✅ |
FlussoARSFAR - Assistenza Residenziale
| Funzionalita | Stato | |---|:---:| | Calcolo ammissioni | ✅ |
FlussoRSA - Residenze Sanitarie
| Funzionalita | Stato | |---|:---:| | Elaborazione dati RSA | ✅ |
Servizi NAR / Tessera Sanitaria
Ts - Tessera Sanitaria
Integrazione con il portale SistemaTS per la verifica e la ricerca di dati sanitari.
Modalita headless (senza browser) - usa axios + cheerio:
import { Ts } from "aziendasanitaria-utils/src/narTsServices/Ts.js";
import { ImpostazioniServiziTerzi } from "aziendasanitaria-utils/src/config/ImpostazioniServiziTerzi.js";
const config = new ImpostazioniServiziTerzi({
ts_username: "CODICE_FISCALE",
ts_password: "PASSWORD"
});
const ts = new Ts(config);
// Ricerca STP/ENI per codice
const risultato = await ts.ricercaStpPerCodice({
prefisso: 'STP', // 'STP' o 'ENI'
codiceAsl: '205',
suffissoCodiceStp: '0000001'
});
// => { error: false, data: { codice_stp_eni, cognome, nome, genere, ... } }
// Ricerca STP/ENI per range
const elenco = await ts.ricercaStpPerRange({
prefisso: 'STP',
codiceAsl: '205',
dal: '0000000',
al: '9999999'
});
// => { error: false, data: [{ codice_stp_eni, cognome, nome, genere, nazionalita }, ...] }
// Ricerca STP/ENI per dati anagrafici
const ricerca = await ts.ricercaStpPerDati({
prefisso: 'STP',
codiceAsl: '205',
cognome: 'ROSSI',
genere: 'M'
});
// Dettaglio da link nella lista
const dettaglio = await ts.getDettaglioStp(elenco.data[0]._detailLink);
// Parsing file forniture assistiti TS (offline, no login)
const { data, stats } = Ts.getDataFromTSFile("/path/to/file.txt");
// --- Cambio medico di base (modulo Gestione Assistiti) ---
// Aggiornamento medico: crea un nuovo periodo di assistenza per l'assistito.
// Vincolo: la data deve essere > data inizio assistenza esistente e <= oggi.
const agg = await ts.aggiornaMedicoAssistito({
cfAssistito: 'RSSMRA80A01F158X',
cfMedico: 'BTASLV97B46F158J', // CF del medico (value della select)
dataAggiornamento: null // opzionale, default = oggi (gg/mm/aaaa)
});
// => { error: false, data: { cfAssistito, cfMedico, dataInizioValidita, codDescRegioneAsl,
// medicoPrecedente: "NOME - CF", medicoPrecedenteCf: "CF", medicoAttuale: "NOME - CF" } }
// Rettifica medico: corregge in place l'associazione corrente (NESSUN vincolo di data).
// Utile per fixare un aggiornamento errato senza creare un nuovo periodo.
const ret = await ts.rettificaMedicoAssistito({
cfAssistito: 'RSSMRA80A01F158X',
cfMedico: 'PRSNNN56B22F158D'
});
// => { error: false, data: { ..., medicoPrecedente, medicoPrecedenteCf, medicoAttuale } }
// In caso di errore: { error: true, data: null, message: "<messaggio dal portale>" }
// --- Copia (PDF) della Tessera Sanitaria ---
// Scarica la copia provvisoria della tessera dato il CF dell'assistito.
const tessera = await ts.getCopiaTesseraSanitaria({
cfAssistito: 'RSSMRA80A01F158X',
filePath: '/tmp/tessera.pdf' // opzionale: se valorizzato salva il PDF su disco
});
// => { error: false, data: { cfAssistito, numeroTessera, dataScadenza, stato,
// pdf: <Buffer>, filePath? } }
// Il PDF è restituito come Buffer (utilizzabile lato server senza UI).
ts.closeHttpSession();Note cambio medico: la tessera viene sempre impostata a CNS e la valenza TEAM "Si". Il portale richiede una doppia conferma (recap + commit), gestita internamente dalle funzioni con due POST sequenziali; il medico precedente viene sempre letto e restituito.
Modalita browser (Puppeteer) - per operazioni legacy:
const page = await ts.getWorkingPage(true); // true = visibile
// ... operazioni con Puppeteer
await ts.doLogout();Nar2 - Nuova Anagrafe Regionale (REST API)
import { Nar2 } from "aziendasanitaria-utils/src/narTsServices/Nar2.js";
const nar2 = new Nar2(impostazioniServiziTerzi);
const token = await nar2.getToken();
// Ricerca assistiti con parametri
const assistiti = await nar2.getAssistitiFromParams({
[Nar2.PARAMS.COGNOME]: 'ROSSI',
[Nar2.PARAMS.NOME]: 'MARIO',
[Nar2.PARAMS.AZIENDA]: '205'
});
// Elenco medici MMG/PLS, con dati dei rapporti individuali e degli indirizzi
const medici = await nar2.getMediciFromNar2({
soloAttivi: true,
aggiungiDatiRapporti: true, // allega `rapporti` e `indirizzi` a ogni medico
parallelsRapporti: 10 // richieste eseguite in parallelo
});
// Solo i rapporti / gli indirizzi di un medico dato il suo pf_id
const rapporti = await nar2.getRapportiMedicoFromId(5860, 'ME');
const indirizzi = await nar2.getIndirizziMedicoFromId(5860, 'ME');
// Lookup comuni (cm_id NAR2) per nome/CAP/ISTAT/catastale, con filtro esatto
// e fallback CAP generico per le città multi-CAP (98167 → 98100)
const {comune, candidati} = await nar2.getComuneNar2({cap: '98167'}); // → MESSINA (id 83)
// Aggiornamento residenza/domicilio (PUT /pazienti/{id}, dryRun default true).
// Sorgenti combinabili: daTs (entrambi dal Sistema TS), residenzaDaTs/domicilioDaTs
// (singola sezione da TS), residenza/domicilio personalizzati {via, civico, cap, comuneId|criterio}
const dry = await nar2.aggiornaIndirizziAssistito(cf, {daTs: true}); // ispeziona dry.diff/warnings
const sent = await nar2.aggiornaIndirizziAssistito(cf, {
residenzaDaTs: true,
domicilio: {via: 'VIA ROMA', civico: '10', cap: '98057'}, // comune risolto dal CAP
dryRun: false
});
// Vedi docs/CAMBIO_MEDICO_NAR2.md §5.b — la verifica indirizzi è lo step standard
// che precede il cambio medico (test interattivo: node ./test-cambio-medico.js)
// ── Inserimento nuovo assistito (fonte: Sistema TS) ──
// Vedi docs/INSERIMENTO_ASSISTITO_NAR2.md. Input minimo: solo il codice fiscale.
// Dati separati TS/NAR2 + esistenza per fonte (pre-check inserimento)
const check = await nar2.verificaAssistitoTsNar2(cf);
// → {ts: {esiste, dati, errore}, nar2: {esiste, dati, errore}, inseribileSuNar2}
// Indirizzo di residenza dal recapito dell'ULTIMA tessera sanitaria (Sistema TS,
// modulo Gestione Assistiti; REGOLA: sempre la più recente, qualunque stato)
const ts = new Ts(impostazioni);
const tessera = await ts.getIndirizzoUltimaTessera({codiceFiscale: cf});
// → {indirizzo, numero_tessera, stato, data_scadenza, regione, asl, ...}
// Orchestratore completo (Assistiti): verifica → indirizzo tessera → POST /pazienti
const assistiti = new Assistiti(configData);
const dryIns = await assistiti.inserisciNuovoAssistitoDaTs(cf); // dryRun default: payload+derivazioni
const ins = await assistiti.inserisciNuovoAssistitoDaTs(cf, {dryRun: false}); // creazione reale → ins.pzId
// (test interattivo: node ./test-cambio-medico.js — se il CF non esiste su NAR2
// propone l'inserimento; modalità [V] verifica TS/NAR2, [T] recapito tessera)Ogni rapporto è normalizzato così (include anche i rapporti non attivi; attivo è true solo se manca la data di fine):
{
id: "75337",
categoria: "mmg", // "mmg" | "pls"
tipoRapporto: "MDB",
descrizioneRapporto: "Medico di base",
email: "...",
telefoni: ["3780818127", "3403896880"], // array, scarta i valori nulli
dataInizio: "25/05/2026", // dd/MM/yyyy
dataFine: null, // null = rapporto attivo
attivo: true,
domicilio: { // indirizzo studio; null se NAR non fornisce il link
comune: "MESSINA",
provincia: "ME",
cap: "98100",
indirizzo: "VIA CENTONZE",
numeroCivico: "72"
}
}Gli indirizzi del medico (legati al medico, non al rapporto) sono restituiti tutti in array, normalizzati così:
{
progressivo: "1",
descrizione: "RESIDENZA", // può essere null
comune: "CANICATTI'",
provincia: "AG",
cap: "92024",
indirizzo: "VIA S. CORAZZINI, 9",
numeroCivico: "1",
dataAttivazione: "21/03/2065", // dd/MM/yyyy
dataDisattivazione: null,
residenza: true, // true se è l'indirizzo di residenza
telefoni: [],
email: null
}Assistiti - Gestione Dati Assistiti
Orchestratore che combina dati da TS, NAR e NAR2.
import { Assistiti } from "aziendasanitaria-utils/src/narTsServices/Assistiti.js";
const assistiti = new Assistiti(configServiziTerzi);
const dati = await assistiti.apriMMGAssistiti(codiceMMG, listaCF);| Funzionalita | Stato | |---|:---:| | Verifica data decesso da TS | ✅ | | Recupero dati da NAR/NAR2 | ✅ | | Generazione documenti DOCX | ✅ | | Elaborazione batch parallela | ✅ |
Medici - Gestione Dati Medici
import { Medici } from "aziendasanitaria-utils/src/narTsServices/Medici.js";
const medici = new Medici(impostazioni, true);| Funzionalita | Stato | |---|:---:| | Ricerca medici MMG/PLS | ✅ | | Integrazione NAR | ✅ | | Report PDF/Excel | ✅ |
Indicatori
Calcolo degli indicatori LEA (Livelli Essenziali di Assistenza).
| Indicatore | Descrizione | |---|---| | D33ZA | Identificazione anziani >75 anni con patologie specifiche (da file ARS) | | D30Z | Indicatore composito SIAD/Hospice |
Configurazione
ImpostazioniServiziTerzi
Credenziali per i servizi esterni:
const config = new ImpostazioniServiziTerzi({
ts_username: "", // Codice Fiscale per Tessera Sanitaria
ts_password: "", // Password TS
nar_username: "", // Username NAR
nar_password: "", // Password NAR
nar2_username: "", // Username NAR2
nar2_password: "" // Password NAR2
});StruttureDistrettiPerProvincia
Configurazione territoriale con distretti, comuni e strutture sanitarie. Include configurazione preconfigurata per Messina.
import { struttureDistrettiMap, distretti, comuniDistretti } from "aziendasanitaria-utils/src/config/sicilia/messina.js";API Reference
Exports principali
import { flussiRegioneSicilia } from "aziendasanitaria-utils";
const {
// Flussi
FlussoM,
FlussoSIAD,
FlussoHOSPICE,
FlussoARSFAR,
FlussoRSA,
// Configurazione
ImpostazioniFlussoM,
ImpostazioniFlussoRSA,
ImpostazioniFlussoHOSPICE,
ImpostazioniFlussoARSFAR,
ImpostazioniMail,
ImpostazioniServiziTerzi,
StruttureDistrettiPerProvincia,
// Servizi
Assistiti,
Medici,
Indicatori,
// Dati regionali
Messina
} = flussiRegioneSicilia;Ts - Metodi STP/ENI (headless)
| Metodo | Parametri | Ritorno |
|---|---|---|
| ricercaStpPerCodice() | { prefisso, codiceAsl, suffissoCodiceStp } | { error, data, message? } |
| ricercaStpPerRange() | { prefisso, codiceAsl, dal, al } | { error, data[], message? } |
| ricercaStpPerDati() | { prefisso, codiceAsl, cognome, genere } | { error, data[], message? } |
| getDettaglioStp() | detailLink | { error, data, message? } |
| closeHttpSession() | - | void |
| Ts.getDataFromTSFile() | filePath | { data[], stats } |
Campi restituiti (dettaglio singolo):
| Campo | Esempio |
|---|---|
| codice_stp_eni | STP1902050000001 |
| cognome | ROSSI |
| nome | MARIO |
| genere | M |
| data_nascita | 01/01/1990 |
| nazionalita | ROMANIA |
| indirizzo | VIA ROMA 1 |
| cap | 98100 |
| comune | MESSINA |
| provincia | ME |
| medico | BIANCHI LUIGI |
| asl_ao | 205 - ASP MESSINA |
| regione | Sicilia |
| tipo_assistito | assistito STP |
| data_inizio_assistenza | 01/01/2024 |
| data_fine_assistenza | 01/07/2024 |
| motivazione_fine_assistenza | FINE ASSISTENZA (DA PARTE DEL SSN) |
Campi restituiti (elenco):
| Campo | Descrizione |
|---|---|
| codice_stp_eni | Codice identificativo |
| cognome | Cognome |
| nome | Nome |
| genere | M/F |
| nazionalita | Nazionalita |
| _detailLink | Link per getDettaglioStp() |
Struttura del Progetto
aziendasanitaria-utils/
├── index.js # Entry point - export principale
├── package.json
│
├── src/
│ ├── m/
│ │ ├── FlussoM.js # Flusso M - Prestazioni specialistiche
│ │ └── DatiStruttureProgettoTs.js
│ │
│ ├── siad/
│ │ └── FlussoSIAD.js # Flusso SIAD - Assistenza domiciliare
│ │
│ ├── hospice/
│ │ └── FlussoHOSPICE.js # Flusso Hospice
│ │
│ ├── ars-far/
│ │ └── FlussoARSFAR.js # Flusso ARS ex FAR
│ │
│ ├── rsa/
│ │ └── FlussoRSA.js # Flusso RSA
│ │
│ ├── narTsServices/
│ │ ├── Ts.js # Tessera Sanitaria (HTTP + Puppeteer)
│ │ ├── Nar.js # NAR legacy (Puppeteer)
│ │ ├── Nar2.js # NAR2 REST API
│ │ ├── Assistiti.js # Gestione assistiti
│ │ └── Medici.js # Gestione medici
│ │
│ ├── config/
│ │ ├── ImpostazioniServiziTerzi.js
│ │ ├── ImpostazioniFlussoM.js
│ │ ├── ImpostazioniFlussoSIAD.js
│ │ ├── ImpostazioniFlussoHOSPICE.js
│ │ ├── ImpostazioniFlussoARSFAR.js
│ │ ├── ImpostazioniFlussoRSA.js
│ │ ├── ImpostazioniMail.js
│ │ ├── StruttureDistrettiPerProvincia.js
│ │ └── sicilia/
│ │ └── messina.js # Config preconfigurata Messina
│ │
│ ├── classi/
│ │ └── Assistito.js # Classe dati assistito
│ │
│ ├── db/
│ │ ├── DBHelper.js
│ │ └── asp_esenzioni.sql
│ │
│ ├── grid/ # Template report HTML
│ │
│ ├── Utils.js # Utility comuni
│ ├── Indicatori.js # Indicatori LEA
│ ├── Procedure.js
│ ├── Stipendi.js
│ ├── CryptHelper.js
│ └── api/
│ └── APIHelper.js
│
├── config/
│ └── config_example.json # Template configurazione
│
└── example.js # Esempio di utilizzoDipendenze Principali
| Categoria | Librerie | |---|---| | HTTP / Scraping | axios, cheerio, puppeteer, puppeteer-extra | | Database | sqlite3, mysql, knex, mdb-reader, lokijs, ioredis | | Documenti | exceljs, xlsx, docx, pdf-lib, libreoffice-convert | | Email | nodemailer, eml-format, @freiraum/msgreader | | Sicurezza | openpgp, argon2, passport, passport-spid | | File | fs-extra, adm-zip, archiver, unzipper, chokidar | | Utilita | lodash, moment-timezone, xml2js, stream-json, winston | | AI | @google/generative-ai |
Configurazione
Creare un file config/config.json partendo dal template:
{
"ts_username": "",
"ts_password": "",
"nar_username": "",
"nar_password": "",
"nar2_username": "",
"nar2_password": ""
}Licenza
MIT - Roberto De Domenico
