Essendo il sistema in questione costruito su un'architettura a eventi, è fondamentale che il payment proxy controlli la versione dell'evento Payment (campo event_version) prima di processarlo e dichiari con quale versione dell'evento quest'ultimo è compatibile. L'evento qui descritto ha versione 2.0.
Step 1
L'utente compila e invia la pratica, la quale viene inserita come evento nel topic applications
Un esempio di evento è il seguente, si faccia particolare attenzione al blocco payment_data:
Il paymentdispatcher legge l'evento della pratica dal topic applications, e dopo aver controllato mediante query su KSQLDB che il pagamento per tale pratica non sia già stato creato, estrae da esso i dati del pagamento, successivamente li riversa in un nuovo evento di tipo Payment e lo inserisce nel topic payments in stato CREATION_PENDING, indicando come chiave dell'evento il valore del campo service_id. Da qui in poi solo il proxy si occuperà di scrivere sul topic payments.
Il proxy legge dal topic payments e, se ha una configurazione attiva per quel pagamento (quindi se l'evento letto ha un tenant_id e un service_id per cui ha una configurazione salvata nello storage del proxy), crea una posizione debitoria sull'Intermediario di riferimento.
Step 3 - Marca da Bollo Digitale
È possibile che la configurazione relativa al pagamento letto dal topic payments abbia configurato al suo interno una marca da bollo digitale. In tal caso, sarà necessario, per ogni marca da bollo digitale, inserire come minimo le seguenti informazioni all'interno del payload da inviare all'intermediario di pagamento con cui ci si sta integrando (in base a poi all'intermediario potrebbero essere necessari altri campi):
Il taglio della marca da bollo o l'importo inserito nella configurazione (per ora l'unico importo supportato è quello da 16 €)
La provincia di residenza del pagatore, la quale si trova nel campo payer.country_subdivision dell'evento payment
L'hash del documento informatico o della segnatura di protocollo cui è associata la marca da bollo digitale (per semplicità il documento in questione sarà il json dell'evento letto dal topic payments)
Il valore del campo reason letto dall'evento nel topic payments o, in assenza di questo, la causale della marca da bollo inserita nella configurazione
Successivamente, sarà necessario:
Valorizzare il campo payment.amount l'importo della marca da bollo inserita in configurazione
Valorizzare il campo payment.due_type con il tipo di dovuto inserito nella configurazione
Valorizzare il campo payment.pagopa_category con il valore della tassonomia di pagoPA contenuta nella configurazione (se presente)
Valorizzare il campo payment.document.hash contenente l'hash del documento informatico o della segnatura di protocollo cui è associata la marca da bollo digitale
Step 3 - Bilancio fisso
ATTENZIONE: questa struttura sarà presente solo sugli eventi payment con event_version valorizzato a 2.0 , sarà necessario dunque controllare la versione dell'evento prima di processarlo
In alcuni casi è possibile che il pagamento che il proxy deve processare presenti un bilancio fisso, ovvero un bilancio i cui importi per ogni voce sono già predeterminati a priori in fase di configurazione del servizio. In tal caso il campo split, quando letto dal proxy per la prima volta, si presenterà come un array vuoto [], il proxy dunque:
Leggerà il campo service_id e reperirà nel mediante esso la configurazione del servizio dentro il quale ci sono le informazioni del bilancio.
Utilizzerà le informazioni ricavate per popolare il payload di creazione della posizione debitoria sull'intermediario di riferimento e per arricchire l'evento appena letto con i dati del bilancio.
Esempio
Nel proxy è configurato per il servizio A il seguente bilancio
In alcuni casi è possibile che il pagamento che il proxy deve processare presenti un bilancio variabile, ovvero un bilancio i cui importi per ogni voce vengono determinati dinamicamente a seconda del cittadino. In tal caso il campo split , quando letto dal proxy per la prima volta, si presenterà con un payload così strutturato
dove il campo code indica un identificativo interno della voce di bilancio determinato in fase di configurazione del servizio, e il campo amount indica l'importo per ogni voce di bilancio. Nel caso in cui il valore di amount sia null significa che quella riga deve essere eliminata in fase di creazione del pagamento sul gateway. Il proxy dunque:
Leggerà il campo service_id e reperirà mediante esso la configurazione del servizio dentro il quale ci sono le informazioni del bilancio.
Per ogni voce di bilancio ricavata dalla configurazione del servizio verrà sostituito l'importo con quello letto nel campo split del pagamento
Utilizzerà le informazioni ricavate per popolare il payload di creazione della posizione debitoria sull'intermediario di riferimento e per arricchire l'evento appena letto con i dati del bilancio.
Esempio 1
Nel proxy è configurato per il servizio A il seguente bilancio
Il pagamento viene passato in stato PAYMENT_PENDING modificando il campo status,
Vengono compilate le informazioni del bilancio nel campo split (se presenti),
Viene compilata l'url per pagare online (links.online_payment_begin.url), la quale è data dalla concatenazione della variabile d'ambiente EXTERNAL_API_URL alla stringa /online-payment/{payment_id}
Viene compilata l'url di ritorno dal pagamento (links.online_payment_landing.url), la quale è data dalla concatenazione della variabile d'ambiente EXTERNAL_API_URL alla stringa /landing/{payment_id}
Viene compilata l'url per pagare offline (links.offline_payment.url), la quale è è data dalla concatenazione della variabile d'ambiente EXTERNAL_API_URL alla stringa /offline-payment/{payment_id}
Viene compilata l'url della ricevuta di pagamento (links.receipt.url), la quale è data dalla concatenazione della variabile d'ambiente EXTERNAL_API_URL alla stringa /receipt/{payment_id}
Viene compilata l'url per richiedere l'aggiornamento del pagamento (links.update.url), la quale è data dalla concatenazione della variabile d'ambiente INTERNAL_API_URL alla stringa /update/{payment_id}
Nota: a differenza dell'altre url, questa viene valorizzata utilizzando una variabile d'ambiente separata in quanto deve essere possibile chiamarla pubblicamente, questo perchè è compito del solo payments-poller richiedere periodicamente l'aggiornamento del pagamento.
Viene compilata l'url per forzare l'annullamento di un pagamento (links.cancel.url), la quale è data dalla concatenazione della variabile d'ambiente EXTERNAL_API_URL alla stringa /payments/{payment_id} . Viene inoltre compilato il metodo con cui chiamare la url (links.cancel.method) con il valore PATCH.
Viene segnato il timestamp di aggiornamento dell'evento di pagamento (updated_at)
Viene infine salvato il pagamento sullo storage e scritto il corrispondente evento aggiornato sul topic payments, indicando come chiave dell'evento il valore del campo service_id.
In caso di risposta negativa, il pagamento viene passato in stato CREATION_FAILED, viene salvato il pagamento sullo storage e viene scritto l'evento aggiornato sul topic payments
Nel core intanto, la UI del cittadino monitora lo stato del pagamento interrogando una tabella su KSQLDB creata a partire dal topic payments, e se in stato PAYMENT_PENDING, vengono mostrate all'utente le opzioni per pagare
Step 4 - "Paga online"
Verra richiamata l'url {EXTERNAL_API_URL}/online-payment/{payment_id} servita dal proxy
Il proxy richiederà all'intermediario di pagamento il link per pagare
Sarà segnato il timestamp di apertura del link (links.online_payment_begin.last_opened_at)
Sarà segnato il timestamp di aggiornamento dell'evento (updated_at)
Il pagamento verrà salvato sullo storage
L'evento aggiornato verrà scritto sul topic payments, indicando come chiave dell'evento il valore del campo service_id
Verrà restituito il link ritornato allo step 2 mediante il quale l'utente verrà rediretto al portale dell'intermediario
Al termine della procedura di pagamento, l'utente verrà fatto ritornare sul dettaglio della pratica mediante l'url di landing specificata in fase di creazione della posizione debitoria (links.online_payment_landing.url) allo step 5, a questa url andrà aggiunto in query string un parametro payment da valorizzare con OK o KO a seconda dell'esito del pagamento
Contemporaneamente, essendo che si passa per il proxy, verrà segnato il timestamp in cui l'utente ha aperto il link di ritorno (links.online_payment_landing.last_opened_at)
Il pagamento verrà portato in stato PAYMENT_STARTED
Sarà segnato il timestamp di aggiornamento dell'evento (updated_at)
Il pagamento verrà salvato sullo storage
L'evento aggiornato verrà scritto sul topic payments, indicando come chiave dell'evento il valore del campo service_id.
Verra richiamata l'url {EXTERNAL_API_URL}/offline-payment/{payment_id} servita dal proxy
Il proxy richiederà all'intermediario di pagamento il pdf dell'avviso di pagamento
Sarà segnato il timestamp di apertura del link (links.offline_payment.last_opened_at)
Sarà segnato il timestamp di aggiornamento dell'evento (updated_at)
Il pagamento verrà salvato sullo storage
L'evento aggiornato verrà scritto sul topic payments, indicando come chiave dell'evento il valore del campo service_id
Verrà eseguito il download del pdf ritornato allo step 1
Step 4 - Annulla pagamento
È possibile che l'operatore abbia necessità di annullare un pagamento mediante l'opzione di registrazione del pagamento, ciò può accadere ad esempio se il cittadino, dopo aver creato il pagamento, decide di non concluderlo, e di pagare invece mediante altri canali creando un nuovo pagamento diverso da quello presente sulla piattaforma. Per evitare quindi di lasciare il pagamento pendente per un tempo indefinito, e per permettere l'avanzamento della pratica all'interno della quale è stato creato tale pagamento, sarà possibile annullare quest'ultimo.
Gli step sono i seguenti:
Verra richiamata l'url PATCH {EXTERNAL_API_URL}/payments/{payment_id} servita dal proxy con payload {"status": "CANCELED"}
Il proxy, dopo aver letto il pagamento dallo storage, segnerà il campo status a CANCELED
Sarà segnato il timestamp di apertura del link (links.offline_payment.last_opened_at)
Sarà segnato il timestamp di aggiornamento dell'evento (updated_at)
Il pagamento verrà salvato sullo storage
L'evento aggiornato verrà scritto sul topic payments, indicando come chiave dell'evento il valore del campo service_id
Step 4 - Dovuti importati da fonte esterna all'Area personale
In alcuni casi è possibile che i pagamenti non siano generati a partire dall'area personale, ma siano invece importati da una fonte esterna. In questo caso gli eventi relativi a tali pagamenti saranno inseriti nel topic payments già in status PAYMENT_PENDING e conterranno al loro interno tutte le informazioni che il proxy normalmente inserisce quando fa passare un pagamento generato dall'area personale dallo status CREATION_PENDING allo status PAYMENT_PENDING.
In tal caso tuttavia, questi pagamenti non saranno presenti sullo storage del proxy, dal momento che questa è un'operazione che normalmente farebbe il proxy. Di conseguenza, nel momento in cui dovesse venir letto un evento in stato PAYMENT_PENDING, ci fosse una configurazione attiva per quest'ultimo (ciò si determina controllando che ci sia sullo storage una configurazione con tenant_id e service_id equivalenti a quelli contenuti nel pagamento) ma non esistesse sullo storage, bisogna semplicemente salvare il pagamento sullo storage.
Nel core intanto, questo tipo di dovuti saranno mostrati nella sezione "Pagamenti" insieme a tutti i pagamenti (importati e non) generati dal cittadino, i dati qui presenti sono estratti mediante interrogazione di una tabella su KSQLDB creata a partire dal topic payments.
Cliccando su "Vedi dettaglio" si andrà sul dettaglio dello specifico pagamento dove saranno mostrate le opzioni per pagare (online, offline)
Step 5
Il payments poller nel frattempo:
Interroga KSQLDB per ottenere lo stato dei pagamenti, e se questi sono in stato PAYMENT_PENDING o PAYMENT_STARTED, eseguirà una chiamata http all'url {INTERNAL_API_URL}/update/{payment_id} servita dal proxy (quella di aggiornamento menzionata allo step 5)
Il proxy a sua volta recupera dallo storage il pagamento, interroga l'intermediario di riferimento per verificare lo stato del pagamento, e in caso lo aggiorna in stato COMPLETE o PAYMENT_STARTED (questa casistica può verificarsi nel caso in cui l'utente paghi ma poi chiuda il browser anziche cliccare sul bottone contenente la landing url)
Se il pagamento viene portato in stato COMPLETE , si dovrà salvare, se presente come informazione ritornata dall'intemediario di riferimento, il timestamp di avvenuto pagamento (payment.paid_at), e l'id della transazione (payment.transaction_id)
Il proxy segna il timestamp in cui è stato aperto il link di aggiornamento (links.update.last_opened_at)
Il proxy segna il timestamp di aggiornamento del pagamento (updated_at)
Il proxy salva il pagamento sullo storage e lo scrive sul topic payments, indicando come chiave dell'evento il valore del campo service_id.
Nota 1: più passa il tempo, più è probabile che il pagamento non venga eseguito dall'utente, di conseguenza ad ogni chiamata del poller verso il proxy, viene incrementato l'intervallo di tempo tra una chiamata e l'altra, ciò viene fatto in base al campo links.update.next_check_at.
Nota 2: non tutti i proxy aggiornano i pagamenti mediante update, alcuni vengono aggiornati predisponendo un'apposita API che l'intermediario di pagamento PagoPA chiama inviando la notifica di completamento del pagamento. Questa viene quindi elaborata dal proxy il quale aggiorna il pagamento portandolo in stato COMPLETE, segna il timestamp di aggiornamento del pagamento (updated_at), lo salva sullo storage e lo scrive sul topic payments, indicando come chiave dell'evento il valore del campo service_id .
Il payment updater monitora lo stato dei pagamenti leggendo dal topic payments, e contestualmente aggiorna lo stato della pratica, se il pagamento è in statoPAYMENT_STARTED, aggiorna lo stato della pratica a "In attesa dell'esito di pagamento", se invece il pagamento è in stato COMPLETE, aggiorna lo stato della pratica a "Accettata" se il pagamento è posticipato, o Inviata se il pagamento è immediato.
TABELLA STATI PAGAMENTO
Gli stati per i quali passa un pagamento durante il suo ciclo di vita sono riassunti nella seguente tabella
STATO PAGAMENTO
DESCRIZIONE
NOTE
CREATION_PENDING
pagamento in attesa di essere creato sul provider di riferimento
CREATION_FAILED
pagamento di cui è fallita la creazione sul provider di riferimento
PAYMENT_PENDING
pagamento creato sul provider di riferimento e in attesa di essere eseguito dall'utente
PAYMENT_STARTED
procedura di pagamento iniziata dall'utente
COMPLETE
pagamento completato a seguito di conferma dal provider di riferimento
PAYMENT_FAILED
pagamento fallito a causa di scadenza del termine ultimo entro cui doveva essere eseguito
nei proxy sviluppati questo stato non è quasi mai stato utilizzato
CANCELED
pagamento annullato forzatamente da un operatore
REQUISITI
Tutti i proxy devono:
Validare gli eventi in input e output
Integrazione con sentry
Healthcheck
Esporre metriche di monitoraggio in formato prometheus