Vai al contenuto

12 — Dettaglio: Riconciliazione Manuale

Approfondimento del capitolo 10 — Monitoraggio e Riconciliazione. Per il dettaglio dei report scambiati, vedi 11 — Dettaglio: Monitoraggio.

Architettura complessiva

Ogni giorno alle 06:00 gt4medServices invia a T4MED il report sintetico (situazione complessiva dall'inizio dell'integrazione) e il report analitico (dettaglio delle ultime due settimane). Il report aggregato consente di verificare rapidamente l'andamento generale del servizio — la sua stessa assenza è un segnale di anomalia. Il report analitico consente a T4MED di effettuare il controllo puntuale degli appuntamenti e dei relativi referti.

Il controllo e il confronto sono eseguiti da T4MED; la gestione delle eventuali discrepanze segue il meccanismo di riconciliazione manuale:

  1. un referente T4MED confronta i report ricevuti con i propri dati e individua le discrepanze;
  2. il referente segnala al servizio assistenza di SINED cosa risulta mancante o discordante;
  3. il servizio assistenza di SINED attiva le procedure di riconciliazione per risolverle.

La responsabilità operativa della riconciliazione resta quindi sempre in carico al servizio assistenza di SINED, unico soggetto con visibilità completa sui propri tentativi di chiamata (incluse le mancate risposte). T4MED resta responsabile del controllo, del confronto e della segnalazione.

Punto aperto: il canale concreto (telefono, e-mail, ticket...) con cui il referente T4MED comunica la segnalazione al servizio assistenza di SINED è da definire con T4MED/TESI.


Endpoint ipotizzati per l'invio dei report

T4MED non ha ancora pubblicato una specifica per l'invio dei report di monitoraggio. Gli endpoint che seguono sono un'ipotesi di lavoro, costruita per analogia con gli endpoint T4MED già noti.

Endpoint T4MED già noti (riferimento)

Base URL: https://biocaretest.evisus.it/api/fhir

Flusso Endpoint T4MED Conformità R4
A POST {base-url} — Bundle transaction CONFORMI
B PUT {base-url}/Appointment/{id} CONFORMI
C DELETE {base-url}/Appointment/{id} CONFORMI
D POST {base-url}/Patient/{cfisc}/$generate-pdf CONFORMI
E POST {base-url} — Bundle transaction; PUT {base-url}/DocumentReference/{id} (solo metadati) CONFORMI

Da questo elenco emergono due pattern già in uso, entrambi candidati per analogia: CRUD REST standard su risorse note (Flussi A, B, C, E) e operazione FHIR custom $nome-operazione (Flusso D).

Opzione 1 — Operazione FHIR custom (per analogia col Flusso D)

Report Sintetico

POST https://biocaretest.evisus.it/api/fhir/$submit-monitoring-summary
Content-Type: application/fhir+json
Authorization: ApiKey <api-key>

Body: la risorsa MeasureReport (vedi 11 — Dettaglio: Monitoraggio).

Report Analitico

POST https://biocaretest.evisus.it/api/fhir/$submit-monitoring-detail
Content-Type: application/fhir+json
Authorization: ApiKey <api-key>

Body: la risorsa Parameters, oppure il Bundle di Task (vedi 11 — Dettaglio: Monitoraggio).

Varianti di risposta

Per entrambi gli endpoint si ipotizzano quattro varianti di risposta.

a) Ricezione semplice

{
  "resourceType": "OperationOutcome",
  "issue": [
    { "severity": "information", "code": "informational", "diagnostics": "Report sintetico ricevuto correttamente." }
  ]
}

b) Dettagliata, senza discrepanze

{
  "resourceType": "OperationOutcome",
  "issue": [
    { "severity": "information", "code": "informational", "diagnostics": "Report sintetico ricevuto e confrontato con i dati T4MED per il periodo 2026-10-01T00:00:00+02:00 - 2027-03-15T00:00:00+01:00. Nessuna discrepanza rilevata." },
    { "severity": "information", "code": "informational", "details": { "text": "Prenotazioni CUP televisita ricevute" }, "diagnostics": "Dichiarate da SINED: 1500. Confermate da T4MED: 1500." }
  ]
}

c) Dettagliata, con discrepanze

{
  "resourceType": "OperationOutcome",
  "issue": [
    { "severity": "information", "code": "informational", "diagnostics": "Report analitico ricevuto: 14 record nel periodo 2027-03-01T00:00:00+01:00 - 2027-03-15T00:00:00+01:00, di cui 12 confermati e 2 con discrepanza." },
    {
      "severity": "warning",
      "code": "not-found",
      "details": {
        "coding": [{ "system": "urn:t4med:error-code", "code": "DISC-002", "display": "Record non pervenuto a T4MED" }],
        "text": "26B001958 / REPO-481207"
      },
      "diagnostics": "SINED dichiara t4medOutcome=success, ma la richiesta non risulta mai ricevuta da T4MED."
    },
    {
      "severity": "warning",
      "code": "conflict",
      "details": {
        "coding": [{ "system": "urn:t4med:error-code", "code": "DISC-003", "display": "Disallineamento di stato" }],
        "text": "26B001960 / REPO-481209"
      },
      "diagnostics": "SINED dichiara reportStatus=signed, mentre la prenotazione risulta a T4MED ancora in attesa di referto."
    },
    {
      "severity": "warning",
      "code": "business-rule",
      "details": {
        "coding": [{ "system": "urn:t4med:error-code", "code": "DISC-004", "display": "Referto fermo in uno stadio intermedio della pipeline" }],
        "text": "26B001962"
      },
      "diagnostics": "SINED dichiara reportStatus=pending da oltre 5 giorni (referto prodotto ma non ancora firmato)."
    }
  ]
}

Questo riscontro sincrono è un primo segnale automatico utile per un controllo rapido lato gt4medServices, ma non sostituisce il canale ufficiale: resta cura del referente T4MED confermare al servizio assistenza di SINED le discrepanze da risolvere, attivando la riconciliazione manuale.

d) Failure

Si riusa lo stesso formato di OperationOutcome di errore già definito da T4MED per i Flussi A-H (vedi 06-response-failure.md):

{
  "resourceType": "OperationOutcome",
  "issue": [
    {
      "severity": "error",
      "code": "required",
      "details": {
        "coding": [{ "system": "urn:t4med:error-code", "code": "PR-002", "display": "Campo obbligatorio mancante" }],
        "text": "Il parametro 'documentId' è obbligatorio per ogni item del report analitico."
      },
      "diagnostics": "transactionId=3b77e0f1-3c2a-4e9b-8a4e-9b0c1d2e3f4a",
      "expression": ["Parameters.parameter[3].part[1]"]
    }
  ]
}

Dizionario dei codici per la risposta OperationOutcome

issue.severity (value set standard FHIR R4):

Codice Significato
fatal Errore bloccante: elaborazione interrotta completamente
error Errore: l'elemento segnalato non è stato elaborato
warning Avviso: elaborato, ma con una condizione da verificare
information Informazione: nessun problema, solo un riscontro o conferma

issue.code — IssueType (sottoinsieme standard FHIR R4 usato):

Codice Significato Usato in
informational Messaggio puramente informativo varianti a/b/c
business-rule Violazione di una regola di business (discrepanza conteggi) variante c (sintetico)
not-found Riferimento a un elemento che non risulta esistere variante c (analitico)
conflict Conflitto di stato fra due versioni dello stesso dato variante c (analitico)
required Elemento obbligatorio mancante nel body inviato variante d (failure)

System: urn:t4med:error-code (custom, in issue.details.coding):

Codice Significato Severity / code tipici
DISC-001 Discrepanza sui conteggi aggregati (sintetico) warning / business-rule
DISC-002 Record dichiarato da SINED ma non pervenuto a T4MED warning / not-found
DISC-003 Disallineamento di stato fra SINED e T4MED warning / conflict
DISC-004 Referto fermo in uno stadio intermedio della pipeline (not-produced/pending/not-sent) oltre una soglia di tempo ragionevole warning / business-rule
PR-001 Formato del report non valido (proposto) error / invalid
PR-002 Campo o identifier obbligatorio mancante error / required
MR-001 Periodo di reporting non valido (proposto) error / invalid

I codici DISC-* qualificano un warning che non blocca la ricezione (HTTP 200, varianti b/c); i codici PR-*/MR-* qualificano un errore che blocca la richiesta (HTTP 4xx/5xx, variante d).

Pro/contro dell'Opzione 1: stesso pattern già usato da T4MED per il Flusso D, con riscontro graduale e formato di errore già standardizzato. Manca però un precedente diretto per un'operazione di "invio dati" (il Flusso D è una lettura/generazione, non un submit).

Opzione 2 — Creazione REST standard (per analogia coi Flussi A, B, C, E)

POST https://biocaretest.evisus.it/api/fhir/MeasureReport
POST https://biocaretest.evisus.it/api/fhir/Parameters

Stesso pattern REST già usato per Appointment e DocumentReference, ma con due perplessità:

  1. Tipi di risorsa: tutti gli endpoint noti di T4MED sono limitati a un insieme chiuso (Appointment, Patient, DocumentReference, Binary). Non è noto se il server accetti genericamente POST su qualunque resourceType, incluso MeasureReport.
  2. Parameters come involucro di operazione: lo standard FHIR R4 definisce Parameters come "involucro di input/output di un'operazione" — il contenitore usato per impacchettare i parametri di una chiamata a un'operazione custom (come la lista di argomenti di una funzione), non come risorsa con un proprio significato di business. Non ha quindi un'identità "di business", non ha parametri di ricerca standard, e molti server FHIR non supportano una create su questo tipo. Una POST /Parameters sarebbe un utilizzo atipico, con comportamento non garantito.

Raccomandazione

Per il report sintetico (MeasureReport, risorsa "normale" pensata per essere creata e conservata) entrambe le opzioni sono plausibili. Per il report analitico in formato Parameters, l'Opzione 1 è preferibile sul piano concettuale. Usando invece un Bundle di Task (vedi 11 — Dettaglio: Monitoraggio) la perplessità si risolve a monte, e anche l'Opzione 2 diventa una scelta solida quanto l'Opzione 1. Resta comunque necessario verificare con T4MED/TESI quale soluzione il loro server sia in grado di supportare.