Manuale Operatore — Integrazione OfficeRnD–Aplus / STID
Versione documento: 3.3 — Ultimo aggiornamento: 2026-05-26
1. A cosa serve questo manuale
Questo documento descrive le funzionalità delle integrazioni automatiche di OfficeRnD (di seguito “ORnD”) con due sistemi esterni:
- Aplus — sistema di controllo accessi tradizionale (sezioni 1–15).
- STID Mobile ID — sistema di VCard mobile (sezione 16).
Le due integrazioni sono indipendenti: un member può essere su una, sull’altra, su entrambe, o nessuna delle due.
Entrambe le integrazioni sono in scrittura solo da ORnD verso il sistema esterno: tutte le modifiche fatte su ORnD vengono replicate automaticamente tramite webhook. Le modifiche fatte manualmente su Aplus o sul portale STID non vengono propagate a ORnD: ORnD resta la sorgente di verità.
2. Concetti di base
Member (ORnD) ↔ User (Aplus). Un membro di ORnD corrisponde a un utente di Aplus. Il legame è mantenuto dalla proprietà custom aplusId sul member di ORnD, che contiene l’IdUser di Aplus.
Company (ORnD) ↔ Company (Aplus). Una company/team di ORnD corrisponde a una company di Aplus. Il legame è mantenuto dalla proprietà custom aplusId sulla company di ORnD, che contiene l’IdCompany di Aplus.
Building (ORnD) ↔ Site (Aplus). Un building di ORnD corrisponde a uno o più site di Aplus. Il legame è mantenuto dalla proprietà custom AplusProfileId sul building (vedi sezione 3).
Booking → Profilo Aplus. Una prenotazione su una risorsa che ha AplusProfileId abilita per il member, nel giorno del booking, il profilo Aplus corrispondente. Per le risorse di tipo DailyPass c’è in più un setup preventivo: vedi capitolo dedicato (sezione 7).
PIN. Il PIN è generato sempre da Aplus, non lo sceglie l’operatore. Il valore generato viene riportato su ORnD nella proprietà AplusPIN del member.
3. Prerequisito fondamentale: il building deve essere abilitato
⚠️ Nessuna azione di integrazione viene eseguita se il building di riferimento del webhook non è abilitato all’integrazione Aplus. Questo è il primo filtro che Charon applica ad ogni evento ricevuto da ORnD: se il building non è abilitato, il webhook viene scartato silenziosamente.
Come si abilita un building: sulla scheda del building (Settings → Locations/Offices) impostare la proprietà custom AplusProfileId con uno o più ID site Aplus.
- Singolo site:
AplusProfileId = 12— il building corrisponde al site 12 di Aplus. - Più site:
AplusProfileId = 12,17,21— il building corrisponde a più site. Quando viene creato un nuovo utente, l’utente viene piazzato sul primo ID della lista (in questo esempio, il site 12).
Conseguenze pratiche:
- Tutte le azioni descritte in questo manuale presuppongono che il building sia abilitato.
- Cambiare l’ordine degli ID nella lista cambia il site di default per i nuovi utenti, ma non sposta gli utenti già esistenti.
- Se un evento (member, booking, membership, …) arriva da un building non abilitato, viene ignorato silenziosamente. Lo si vede nei log come “Building non di interesse — ignora”.
4. Quando vengono create company e member su Aplus
La creazione di una company o di un member su Aplus non avviene mai come semplice riflesso di un’azione di creazione anagrafica su ORnD. Charon crea l’entità su Aplus solo in due situazioni:
4.1 Forzatura manuale dall’operatore
L’operatore imposta aplusId = -1 sulla proprietà custom della company o del member in ORnD. Vedi sezione 5.
4.2 Necessità di abilitare un profilo
Charon crea automaticamente company e/o member su Aplus quando ne ha bisogno per assegnare un profilo, in due casi:
- Attivazione di una membership (o pass) il cui piano/risorsa abbia la proprietà
AplusProfileIdvalorizzata. Vedi sezione 8. - Booking del giorno su una risorsa con
AplusProfileIdvalorizzato (incluse le risorse di tipoDailyPass). Vedi sezioni 6 e 7.
In sintesi: se non c’è né una forzatura né una necessità reale di abilitare un profilo, una nuova company o un nuovo member su ORnD non vengono propagati a Aplus.
5. Forzare azioni dall’interfaccia ORnD
Tutti i “trigger manuali” funzionano allo stesso modo: l’operatore imposta un valore speciale in una proprietà custom; ORnD invia il webhook a Charon; Charon riconosce il valore ed esegue l’operazione.
5.1 Forzare la creazione/sincronizzazione di una company su Aplus
- Quando usarlo: la company esiste su ORnD ma non risulta su Aplus, oppure si vuole rigenerare il legame.
- Cosa fare: in ORnD, aprire la company, andare nella sezione “Properties”, impostare la proprietà
aplusIdal valore-1e salvare. - Cosa succede: Charon riceve il webhook
company.updated, crea la company su Aplus (o riusa quella esistente con lo stesso nome) e scrive inaplusIdl’identificativo Aplus reale. - Verifica: riaprire la company dopo qualche secondo e controllare che
aplusIdcontenga un numero positivo.
5.2 Forzare la cancellazione di una company da Aplus
- Quando usarlo: si vuole rimuovere la company da Aplus mantenendola su ORnD.
- Cosa fare: impostare la proprietà
aplusIddella company al valore-2e salvare. - Cosa succede: Charon riconosce
-2come marcatore di cancellazione, recupera l’identificativo Aplus precedente, cancella la company su Aplus e disabilita gli utenti collegati. - ⚠️ Attenzione: operazione irreversibile lato Aplus. Per ricreare la company successivamente, impostare
aplusIda-1come al punto 5.1.
5.3 Forzare la creazione/sincronizzazione di un member su Aplus
- Quando usarlo: il member esiste su ORnD ma non risulta su Aplus, oppure si vuole rigenerare il legame senza aspettare un booking o l’attivazione di una membership.
- Pre-requisito: la company del member deve avere un
aplusIdpositivo. Se non ce l’ha, l’operazione viene saltata: eseguire prima il punto 5.1. - Cosa fare: aprire il member, impostare la proprietà
aplusIdal valore-1e salvare. - Cosa succede: Charon crea l’utente su Aplus (piazzandolo sul primo site indicato in
AplusProfileIddel building) e aggiornaaplusIdsu ORnD. Se in passato esisteva già un utente Aplus con la stessa email, l’identificativo precedente viene ripristinato (no duplicati).
5.4 Forzare la rigenerazione del PIN di un member
- Quando usarlo: il member ha perso il PIN, o lo si vuole resettare.
- Pre-requisito: il member deve avere un
aplusIdvalido (positivo). - Cosa fare: impostare la proprietà
AplusPINal valore-1e salvare. - Cosa succede: Charon chiede a Aplus di generare un nuovo PIN a 4 cifre, lo riceve dalla risposta SOAP e lo scrive su ORnD nella stessa proprietà
AplusPINsovrascrivendo il-1. - Verifica: riaprire il member dopo qualche secondo:
AplusPINdeve contenere un numero a 4 cifre. Lo stesso valore deve essere presente nel campoPindell’utente in Aplus. - Nota: il PIN è sempre deciso da Aplus. Non impostare valori diversi da
-1: il sistema non li riconosce come trigger di rigenerazione.
5.5 Far rielaborare un member senza modifiche reali
Salvare il member su ORnD senza modifiche significative non scatena alcuna azione (Charon riconosce il caso “NOP” e lo ignora). Per forzare la rielaborazione completa, usare i trigger 5.3 / 5.4 a seconda di cosa serve.
6. Bookings — come vengono trattati
Le prenotazioni su risorse normali (cioè non DailyPass) vengono gestite con la seguente logica:
6.1 Risorsa coinvolta
Una risorsa è considerata “rilevante per Aplus” se la sua proprietà AplusProfileId è valorizzata con un ID profilo Aplus positivo. Se la proprietà manca, la risorsa è ignorata e nessuna azione viene fatta su Aplus (log: “Resource not managed”).
6.2 Webhook in tempo reale alla creazione/modifica del booking
Quando un utente crea o modifica un booking su una risorsa rilevante, Charon riceve il webhook booking.created o booking.updated. A questo punto:
- Se il booking è per oggi: Charon procede subito ad abilitare il profilo Aplus sull’utente per la durata del booking. Se necessario, crea anche company e member su Aplus (vedi sezione 4.2).
- Se il booking è per un giorno futuro: Charon registra l’evento ma non esegue ancora alcuna azione su Aplus. L’azione verrà eseguita dal processo today (sezione 9) la mattina del giorno del booking.
6.3 Cancellazione di un booking
Quando un booking viene cancellato (webhook booking.deleted), Charon rimuove il profilo di quel booking dal member, se era stato assegnato.
6.4 Modifica della data o del member del booking
Una modifica del booking viene trattata come un nuovo booking (rimuove il profilo precedente se necessario e riassegna). Anche qui vale la regola: l’azione su Aplus avviene solo se la data risultante è oggi; altrimenti la rielaborazione la fa il processo today.
7. DailyPass — capitolo dedicato
Una risorsa “DailyPass” è una risorsa prenotabile in ORnD che, ad ogni booking, assegna al member un profilo di accesso Aplus per l’intera giornata. È pensata per gli ingressi a giornata di non-residenti, ospiti, freelance occasionali.
7.1 Configurazione (una sola volta per risorsa)
- Su ORnD, aprire la risorsa.
- Impostare il type della risorsa esattamente a
DailyPass(con la maiuscola, senza spazi). - Nella sezione Properties, aggiungere/impostare la proprietà
AplusProfileIdcon il valore dell’IdProfileAplus corrispondente (numero intero positivo).
Se manca anche solo una di queste due condizioni la risorsa viene trattata come una risorsa normale (sezione 6) e la logica DailyPass non si attiva.
7.2 Setup preventivo (alla creazione/modifica del booking)
A differenza delle risorse normali, per una risorsa DailyPass Charon esegue subito un “setup preventivo” anche se il booking è per un giorno futuro:
- Se la company del member non ha
aplusId, viene creata su Aplus. - Se il member non ha
aplusId, viene creato su Aplus. - Se il member non ha
AplusPIN, viene richiesto a Aplus un nuovo PIN e scritto su ORnD. - Il booking viene confermato (passa da tentative a confirmed).
Questo serve perché il membro deve poter ricevere il PIN e tutte le informazioni d’accesso prima del giorno del booking.
7.3 Abilitazione del profilo nel giorno del booking
L’aggiunta del profilo DailyPass al member avviene:
- Subito, se il booking è per oggi (lo gestisce il webhook in tempo reale).
- Altrimenti, la mattina del giorno del booking, attraverso il processo today (sezione 9).
7.4 Cancellazione di un booking DailyPass
Alla cancellazione, il profilo DailyPass viene rimosso dall’utente Aplus. Company e member rimangono su Aplus; PIN e legami non vengono toccati.
8. Membership e Pass — capitolo dedicato
Le membership e i pass di ORnD modellano l’iscrizione di un member a un piano (mensile, annuale, day-pass ricorrente, ecc.). Quando il piano ha la proprietà AplusProfileId valorizzata, l’attivazione/disattivazione della membership si traduce in apertura/chiusura del corrispondente profilo Aplus per tutti i membri della company.
8.1 Configurazione del piano
- In ORnD, Settings → Plans, aprire il piano e nella sezione Properties impostare
AplusProfileIdcon l’IdProfileAplus che si vuole assegnare ai member di quella membership. - Se il piano non ha questa proprietà, l’evento di membership viene ignorato (log: “Plan has no AplusProfileId — skipping”).
8.2 Attivazione di una membership
Alla creazione di una membership (o all’attivazione di una già esistente), Charon:
- Crea su Aplus la company del team se manca (vedi sezione 4.2).
- Crea su Aplus ogni member del team che ancora non esiste in Aplus.
- Assegna a tutti i member il profilo Aplus indicato in
AplusProfileIddel piano, con le date di inizio e fine della membership.
L’operazione è puntuale: si applica solo alla membership che ha scatenato il webhook (gli altri profili dei member non vengono toccati).
8.3 Modifica di una membership attiva
Una modifica della membership ancora attiva (per esempio cambio data fine, cambio piano se il nuovo piano ha lo stesso AplusProfileId) viene trattata come una riassegnazione dello stesso profilo con le nuove date:
- Se le date sono cambiate, il profilo Aplus viene rimosso e ri-assegnato con le date nuove.
- Se le date sono uguali, l’operazione è no-op.
8.4 Terminazione, cancellazione o scadenza di una membership
Una membership si chiude in tre modi diversi, tutti trattati allo stesso modo da Charon:
- Cancellazione esplicita (
membership.deleted). - Aggiornamento con
calculatedStatusdiverso daactive(per esempio “ended”, “suspended”, …). - Scadenza naturale (la data fine è passata).
In tutti questi casi Charon rimuove il profilo Aplus indicato in AplusProfileId del piano da tutti i member del team. Company e member di Aplus non vengono toccati: continuano ad esistere ma perdono l’accesso al profilo. Se il member non ha altri profili attivi (membership o booking), di fatto non potrà più accedere.
8.5 Cambio di piano
Se la membership del member viene cambiata sostituendo il piano:
- Se il vecchio piano aveva
AplusProfileIde il nuovo no: il profilo viene rimosso. - Se il vecchio piano non aveva
AplusProfileIde il nuovo sì: il profilo viene aggiunto. - Se entrambi hanno (lo stesso)
AplusProfileId: nessun cambio. - Se entrambi hanno
AplusProfileIddiversi: il sistema rimuove il vecchio e aggiunge il nuovo.
9. Processo “today” — esecuzione giornaliera
Il processo today è una rielaborazione batch che gira una volta al giorno (di norma la mattina presto, da scheduler/cron) e si occupa di portare la situazione su Aplus in linea con la giornata appena iniziata. È indispensabile: senza di esso i booking creati in giorni precedenti non risulterebbero abilitati su Aplus la mattina del booking.
9.1 Cosa fa il processo today
- Pulizia profili scaduti. Interroga Aplus per ottenere la lista dei profili la cui data fine è ormai passata e li rimuove uno per uno dagli utenti corrispondenti.
- Caricamento dei booking del giorno. Legge da ORnD tutti i booking che hanno inizio nel giorno corrente.
- Per ogni booking:
- Se la risorsa è DailyPass: esegue handle_daily_pass_booking (crea company/member/PIN se mancano, aggiunge il profilo per la giornata) e registra l’ingresso (timbratura su Aplus + check-in su ORnD).
- Se la risorsa è normale ma rilevante per Aplus: esegue handle_booking_created (crea company/member se mancano, aggiunge il profilo per la durata del booking).
- Se la risorsa non è rilevante: salta.
- Se la risorsa è DailyPass: esegue handle_daily_pass_booking (crea company/member/PIN se mancano, aggiunge il profilo per la giornata) e registra l’ingresso (timbratura su Aplus + check-in su ORnD).
9.2 Conseguenze importanti per l’operatore
- Un booking creato per oggi viene gestito subito; un booking creato per un giorno futuro verrà gestito solo dal processo today della mattina del booking.
- Se il processo today non parte (per esempio per un blocco dello scheduler), i booking per quel giorno non vengono abilitati su Aplus finché non si esegue manualmente. Segnalare al team tecnico se ci si accorge di accessi mancanti su un certo giorno.
- La pulizia profili scaduti è anch’essa attivata dal processo today: se non gira, profili obsoleti restano sui member fino a esecuzione successiva.
10. Mappa dei campi sincronizzati
La sincronizzazione è limitata ai campi seguenti. Altri campi (telefono, indirizzo, partita IVA, ecc.) non sono attualmente sincronizzati.
| ORnD | Aplus | Note |
|---|---|---|
Building: AplusProfileId |
Site ID | Lista di ID separati da virgola. Il primo è il site dove vengono creati i nuovi utenti. |
| Member: nome / cognome | User: nome / cognome | Sincronizzati su create e update. |
| Member: email | User: email | Chiave univoca in Aplus, blocca duplicati. |
Member: aplusId |
User: IdUser |
Legame primario gestito da Charon. |
Member: AplusPIN |
User: Pin |
Generato da Aplus. -1 = trigger rigenerazione. |
| Company: nome | Company: nome | Chiave univoca in Aplus. |
Company: aplusId |
Company: IdCompany |
Legame primario. -1 = trigger creazione, -2 = cancellazione. |
Resource type = DailyPass + AplusProfileId |
Profile assignment | Vedi sezione 7. |
Resource: AplusProfileId (non DailyPass) |
Profile assignment | Vedi sezione 6. |
Plan: AplusProfileId |
Profile assignment | Vedi sezione 8. |
11. Modalità test (per il team tecnico)
L’integrazione supporta tre modalità di esecuzione, attivate tramite il parametro test o variabili d’ambiente:
test=0(produzione): scrive realmente su Aplus.test=1(debug): scrive realmente su Aplus ma con log estesi.test=2(mock): non contatta Aplus, simula le risposte (utile per provare il flusso senza impatti).
In ambiente di sviluppo è possibile usare lo strumento lancio_charon.php per rieseguire un payload archiviato (parametri: site, fout_file, test). In produzione si lavora sempre con test=0.
12. Diagnostica — significato dei messaggi più frequenti
| Messaggio | Significato e azione |
|---|---|
| “Building non di interesse — ignora” / “Office N non ha AplusProfileId configurato. Skip.” | Il building del webhook non ha AplusProfileId: tutta l’integrazione è disabilitata per quel building. Vedi sezione 3. |
| “Resource not managed” / “Resource is not a managed bookable resource — skipping” | La risorsa del booking non ha AplusProfileId e non è di tipo DailyPass. Vedi sezioni 6 e 7. |
| “Booking is not for today, skipping” | Il booking è per un giorno futuro. Verrà gestito dal processo today nel giorno corretto. Vedi sezione 9. |
| “NOP-aplusId” / “NOP-update” | Webhook ricevuto ma senza modifiche sostanziali per Aplus. Nessuna azione, comportamento corretto. |
| “Plan has no AplusProfileId — skipping” | Il piano della membership/pass non ha AplusProfileId. Vedi sezione 8. |
| “Membership plan/resource has no AplusProfileId — skipping” | Variante del precedente, lato membership. Stessa azione: configurare il piano. |
| “Member previously had aplusId=XYZ, restoring instead of creating new” | Il member ha avuto in passato un utente Aplus con la stessa email: Charon ripristina l’ID precedente invece di creare un duplicato. Comportamento corretto. |
| “AplusPIN=-1, assigning PIN” | Trigger di rigenerazione PIN ricevuto e in lavorazione. Vedi 5.4. |
| “assign_PIN: APLUS rejected request” | Aplus non ha generato il PIN. Cause tipiche: utente non esistente o disabilitato. Verificare che il member abbia aplusId valido. |
| “today.inc: Expired profiles cleanup completed” | Pulizia giornaliera dei profili scaduti completata. Informativo. |
| “today.inc: No bookings for today” | Nessun booking da elaborare oggi. Informativo. |
| “MOCK: …” | Modalità mock attiva: nessuna scrittura reale su Aplus. Se appare in produzione, segnalare al team tecnico. |
| “AplusSoapClient::addProfileToUser(): Argument #4 ($expiredProfileDate) must be of type string, null given” | Bug risolto il 2026-05-26: una membership/booking arrivava senza endDate. Charon ora usa 2099-12-31T23:59:59 come default convenzionale per “no expiry”. Se ricompare con altro argomento (#3 startProfileDate), segnalare al team tecnico. |
13. Casi pratici (cookbook)
Caso A — Abilitare un nuovo building all’integrazione
- Aprire il building in ORnD.
- Nelle Properties impostare
AplusProfileIdcon l’ID site Aplus (o lista separata da virgola, vedi sezione 3). - Salvare. Da questo momento tutti i webhook relativi al building verranno elaborati.
Caso B — Nuovo membro che entra in una azienda esistente
- Creare il member in ORnD nella company corretta.
- Charon non crea l’utente su Aplus fino a quando non serve davvero (membership attivata, booking del giorno) oppure finché l’operatore non forza con
aplusId = -1. - Quando l’utente verrà creato, il PIN sarà generato automaticamente e visibile in
AplusPINsul member.
Caso C — Voglio creare subito company/member e PIN su Aplus
- Aprire la company in ORnD, impostare
aplusId = -1, salvare e attendere cheaplusIddiventi positivo. - Aprire il member, impostare
aplusId = -1e salvare. Attendere cheaplusIddiventi positivo. - Sempre sul member, impostare
AplusPIN = -1e salvare. Attendere cheAplusPINcontenga un numero a 4 cifre. - Comunicare il PIN al membro.
Caso D — Reset del PIN su richiesta del membro
- Aprire il member in ORnD.
- Impostare
AplusPINa-1e salvare. - Attendere qualche secondo, riaprire il member, leggere il nuovo PIN dalla proprietà
AplusPIN. - Comunicarlo al membro.
Caso E — Cessazione di un’azienda
- Aprire la company in ORnD.
- Impostare
aplusIda-2e salvare. - Charon cancella la company su Aplus e disabilita gli utenti associati.
Caso F — Nuova risorsa giornaliera (es. “DailyPass Sala B”)
- Chiedere al team tecnico l’
IdProfileAplus corretto. - In ORnD, sulla risorsa, impostare type =
DailyPasse aggiungere la proprietàAplusProfileIdcon quel valore. - Testare con un booking di prova in giornata: il booking deve passare da tentative a confirmed e il membro deve poter accedere.
Caso G — Membership chiusa anticipatamente
- In ORnD chiudere/terminare la membership del member (cambio status o impostazione data fine al passato).
- Charon riceve il webhook
membership.updatedcon stato non più attivo e rimuove il profilo Aplus dal member. - Il member, se non ha altre membership/booking attivi, da quel momento non riuscirà più ad accedere.
Caso H — Booking per la settimana prossima che “non funziona”
- Verificare che la risorsa abbia
AplusProfileId(o type=DailyPass+AplusProfileId). - Ricordare: i booking per giorni futuri vengono abilitati su Aplus solo la mattina del giorno del booking, dal processo today.
- Se il giorno del booking arriva e l’accesso continua a non funzionare, segnalare al team tecnico: probabilmente il processo today non è partito.
14. Cosa NON va fatto
- Non modificare il PIN manualmente su Aplus: la prossima rigenerazione su ORnD lo sovrascriverebbe. Per cambiare il PIN si usa sempre il trigger
AplusPIN=-1su ORnD. - Non impostare
aplusIda valori arbitrari diversi da-1,-2o dall’identificativo Aplus reale: il sistema rifiuta o ignora valori non previsti. - Non creare manualmente la stessa company o lo stesso utente sia su ORnD che su Aplus: lasciare che sia Charon a propagare. Se entrambi esistono già da prima dell’integrazione, allineare i due tramite
aplusId=-1(Charon riusa l’entità Aplus esistente con stesso nome/email). - Non duplicare l’email di un member: è chiave univoca su Aplus e blocca la creazione.
- Non cambiare l’
AplusProfileIddi un building a integrazione attiva senza coordinarsi con il team tecnico: gli utenti già creati restano sul vecchio site.
15. Glossario rapido dei marcatori
| Marcatore | Posizione | Effetto |
|---|---|---|
AplusProfileId = <id> (o lista id1,id2,…) |
Building | Abilita il building all’integrazione. Il primo ID è il site di default per i nuovi utenti. |
aplusId = -1 |
Company | Crea (o riusa) la company su Aplus. |
aplusId = -1 |
Member | Crea (o ripristina) l’utente su Aplus. |
aplusId = -2 |
Company | Cancella la company da Aplus. |
AplusPIN = -1 |
Member | Rigenera il PIN. |
AplusProfileId = <id> |
Risorsa “normale” | Rende la risorsa rilevante per Aplus: i booking attivano il profilo. |
type = DailyPass + AplusProfileId |
Risorsa | Abilita la logica DailyPass (setup preventivo + profilo per la giornata). |
AplusProfileId = <id> |
Piano (membership/pass) | Abilita assegnazione/rimozione profilo per chi ha quel piano. |
16. STID Mobile ID — integrazione VCard
STID Mobile ID è un sistema di credenziali virtuali su smartphone (VCard). L’integrazione consente di emettere automaticamente VCard ai member di ORnD e di revocarle alla cessazione del rapporto. È separata e indipendente dall’integrazione Aplus.
16.1 Concetti di base
Tenant STID. Un tenant rappresenta l’organizzazione cliente lato STID. Contiene un site (insieme di varchi gestiti), una o più reader configuration (configurazioni dei lettori), uno o più card layout (estetica della VCard).
VCard. Una credenziale virtuale legata a un singolo utente, identificata da un UUID. Ha uno stato (Sent, Active, Revoked…) e un periodo di validità.
Credito. Ogni VCard creata consuma 5 crediti dal saldo del tenant. Crearla e cancellarla prima che l’utente la attivi non consuma crediti.
16.2 Prerequisito: spazio abilitato all’integrazione
L’integrazione STID si attiva per uno spazio (es. betakeoff, stella33) solo se il team tecnico ha valorizzato le variabili $stid_enabled = true e le credenziali nel file web/set_ornd1.inc. Senza questo, qualunque trigger su STidEnabled viene ignorato.
Al 2026-05-19 lo stato è:
betakeoff— STID attivo (rollout iniziale).stella33— STID disattivo (rollout previsto dopo betakeoff).
16.3 Trigger manuale: il campo STidEnabled sul member
Su ORnD, ogni member ha una property custom STidEnabled (string). Il valore di questa property guida l’integrazione:
| Valore | Significato |
|---|---|
(vuoto) o 0 |
Member non ancora gestito da STID. Charon può emettere una VCard automaticamente quando il member viene coinvolto in un booking (vedi 16.4). |
-1 |
Forza emissione della VCard (anche se non c’è un booking che la giustifichi). |
-2 |
Forza revoca della VCard esistente. Dopo la revoca, STidEnabled torna a vuoto. |
UUID (32 caratteri esadecimali, es. 87e1ba60893e484d8a36ffc438fc2c10) |
La VCard è stata emessa con questo UUID. Charon lo gestisce automaticamente. |
⚠️ Importante: i valori
-1/-2li imposta l’operatore; il valore UUID viene scritto in automatico da Charon dopo la creazione. L’operatore non deve modificare manualmente l’UUID.ℹ️ Stato dopo revoca: a partire dalla versione 3.1 del manuale, dopo una revoca (sia esplicita
-2sia automatica dal job mensile, vedi 16.9) il campoSTidEnabledtorna a stringa vuota. Non c’è più il “reuse” della VCard precedente: una nuova richiesta di accesso genera una nuova VCard con un nuovo UUID (consumando 5 crediti). L’utente vedrà nella sua app sia la VCard vecchia (revocata) sia la nuova.
16.4 Auto-emissione VCard al primo booking
Charon emette automaticamente una VCard a qualunque member che venga coinvolto in un booking (su qualsiasi risorsa rilevante per Aplus), purché il campo STidEnabled del member sia ancora vuoto o 0.
Condizioni:
- L’integrazione STID è attiva per lo spazio (
$stid_enabled = trueinset_ornd1.inc). - Il member ha
STidEnablednon valorizzato (vuoto o0); se contiene già un UUID,-1o-2, l’auto-emissione non interviene e Charon rispetta lo stato esistente. - Il booking è di qualunque data (anche futura): l’utente riceve la VCard subito, con tempo di installare l’app STID e attivarla prima del giorno del booking.
Casi pratici dove serve:
- Un ospite esterno prenota una sala riunioni → riceve automaticamente la VCard per accedere il giorno del booking.
- Un freelance prenota un DailyPass → VCard emessa al momento della prenotazione.
- Un member interno non ancora “censito” su STID prenota una risorsa → viene preso in carico anche da STID.
Per disabilitare l’auto-emissione su un singolo member: oggi non c’è un opt-out esplicito. Se serve, basta cancellare la VCard impostando STidEnabled = -2 dopo l’emissione automatica (la VCard viene revocata e il campo torna vuoto).
16.5 Trigger a livello company (emissione/revoca di massa)
In aggiunta al trigger sul singolo member, anche la company ha la property custom STidEnabled (stringa). Permette di gestire in massa tutti i member del team con una sola azione.
Valore su company.STidEnabled |
Effetto |
|---|---|
-1 |
Emissione massiva: ogni member del team che non ha già un UUID riceve subito una VCard (stid_handle_request). I member con UUID già esistente NON sono toccati (evita doppie emissioni). I member con marker -1 pendente vengono comunque promossi a UUID; quelli con marker -2 vengono saltati (rispetta la revoca individuale richiesta). |
-2 |
Revoca massiva: ogni member del team con UUID viene revocato. STidEnabled su ciascun member torna a vuoto. |
| altri valori | Ignorato. |
Marker permanente: dopo l’azione, company.STidEnabled resta sul valore impostato. Questo serve per la regola di ereditarietà: ogni nuovo member creato in una company con STidEnabled = -1 riceve subito una VCard alla creazione (Charon scrive direttamente l’UUID sul nuovo member, senza passare dallo stato intermedio -1).
Casi d’uso tipici:
- Onboarding di tutta una nuova azienda cliente: imposta
company.STidEnabled = -1una volta, e tutti i collaboratori esistenti + futuri ricevono la VCard. - Disdetta di un’azienda intera: imposta
company.STidEnabled = -2, tutti i collaboratori vengono revocati con un’unica azione.
Costo crediti: -1 sulla company spende 5 crediti per ogni member del team senza VCard. Valutare il costo prima di salvare.
16.6 Forzare l’emissione di una VCard (manuale)
Quando usarlo: un member deve avere accesso tramite STID e non ha ancora una VCard, oppure ha una VCard revocata e la si vuole riattivare.
Pre-requisito: il member deve avere almeno una membership attiva o un booking futuro/in corso che gli garantiscano una data fine validità. Se manca, l’operazione viene rifiutata.
Cosa fare:
- Su ORnD, aprire il member.
- Nella sezione Properties, impostare
STidEnabledal valore-1. - Salvare.
Cosa succede:
- Charon riceve il webhook
member.updated. - Calcola la data fine validità VCard:
- max(
endDate) tra le membership attive del team del member; - oppure, in mancanza di membership, max(
enddel booking) + 15 minuti.
- max(
- Chiede a STID di creare una nuova VCard, oppure (se esiste un UUID precedente revocato) chiama il path di
reuse. - STID invia automaticamente l’email di invito all’indirizzo del member.
- L’UUID della VCard viene scritto in
STidEnabledsu ORnD (sovrascrivendo il-1). - Vengono consumati 5 crediti dal tenant STID (solo nel caso di nuova create, il
reusenon consuma crediti).
Verifica:
- Riaprire il member dopo qualche secondo:
STidEnableddeve contenere un UUID di 32 caratteri esadecimali. - Il member deve aver ricevuto l’email di invito.
- Cliccando il link nell’email (idealmente dall’app STID Mobile ID sullo smartphone) la VCard viene attivata e diventa visibile nel portale STID.
16.6-bis Legame STID ↔ APLUS (propagazione del codice)
Dalla versione 3.3 del manuale (2026-05-26), quando Charon emette una VCard STID, propaga automaticamente il codice di lettura (PrivateId STID, a 10 cifre) anche all’utente APLUS via la SOAP AddCodeToUser. Serve per legare la credenziale mobile all’utente APLUS: quando l’utente avvicina lo smartphone al lettore, il lettore presenta ad APLUS un codice numerico; APLUS riconosce l’utente solo se quel codice gli è stato registrato in precedenza.
Flusso:
- Charon chiede a STID un PrivateId di lunghezza esatta 10 cifre (max 5 retry se la prima generazione è di lunghezza diversa).
- Crea la VCard STID con quel PrivateId.
- Se il member ha
aplusIdvalido, chiamaAddCodeToUsersu APLUS con:code = PrivateId STID,CodeExpired = ValidityEndDateUtc della VCard STID,UserId = aplusId.
Pre-requisito: il member deve avere aplusId positivo. Se manca, la propagazione viene saltata e loggata come skipping APLUS code propagation.
Errori non fatali: se AddCodeToUser fallisce (APLUS irraggiungibile, codice già esistente, ecc.), la VCard STID resta valida e l’email d’invito è già stata inviata. L’operatore può riprovare la propagazione: vedi caso N nel cookbook.
16.7 Forzare la revoca di una VCard (manuale)
Quando usarlo: un member non deve più accedere via STID (uscita dall’azienda, smarrimento del telefono, ecc.).
Pre-requisito: la VCard deve essere attivata (Status = Active). Le VCard ancora in stato “Sent” (mai attivate dall’utente) non possono essere revocate; vanno invece cancellate dal portale STID dal team tecnico.
Cosa fare:
- Su ORnD, aprire il member.
- Impostare
STidEnabledal valore-2. - Salvare.
Cosa succede:
- Charon revoca la VCard su STID.
- Il valore
STidEnabledtorna a stringa vuota. - Se serve riemettere una VCard in futuro per lo stesso member, basta impostare di nuovo
STidEnabled = -1(oppure lasciare che ci pensi l’auto-emissione di 16.4 al prossimo booking): verrà generata una nuova VCard con un nuovo UUID (5 crediti).
16.8 Cancellazione di un member con VCard
Quando un member viene cancellato da ORnD, se aveva un UUID valorizzato in STidEnabled, Charon chiama l’endpoint di cancellazione STID per rimuovere la VCard definitivamente.
16.9 Aggiornamento automatico della validità (extend giornaliero)
Charon ricalcola la data fine validità VCard ad ogni evento che la può aver cambiata:
- Modifica di una membership del team → se la nuova data fine è diversa da quella in STID, la VCard viene aggiornata.
- Creazione/cancellazione di un booking → ricalcolo della data fine se il booking concorre alla validità.
- Ogni giorno (processo
today.today): per ciascun member con UUID, ricalcolo della data fine e aggiornamento STID se diversa.
L’operatore non deve fare nulla in questi casi: tutto è automatico. L’estensione non consuma crediti.
16.10 Revoca centralizzata mensile (1° del mese)
A partire dalla versione 3.1 del manuale, la revoca delle VCard scadute non è più giornaliera ma centralizzata:
- Il 1° giorno di ogni mese, durante l’esecuzione di
today.today, Charon scansiona tutti i member conSTidEnabled = UUIDe revoca quelli la cui validità è scaduta nel mese precedente (cioè data fine compresa fra il 1° e l’ultimo giorno del mese passato). - Per i member la cui validità è scaduta nel mese corrente (es. il 15 giugno e siamo al 20 giugno), la VCard resta valida lato STID fino al 1° luglio. La VCard “scaduta” non viene presentata ai varchi nel periodo intermedio (i varchi rifiutano se
endDateè passata), ma Charon non la rimuove dal portale STID prima del 1° del mese seguente. - Quando la revoca avviene,
STidEnabledsu ORnD torna a stringa vuota.
Questo permette di raggruppare la pulizia STID in un’unica passata mensile invece di farne una al giorno.
16.11 Mappa dei campi STID
| ORnD | STID | Note |
|---|---|---|
| Member: nome / cognome | VCard: FirstName / LastName | Sincronizzati al create e su update identità. |
| Member: email | VCard: Email | Destinatario dell’email di invito. |
Member: STidEnabled |
VCard: Uuid | Quando contiene un UUID = legame attivo. |
Membership: endDate |
VCard: ValidityEndDateUtc | La data fine VCard è il max delle membership attive del team. |
| Booking: fine + 15 minuti | VCard: ValidityEndDateUtc | Solo se non ci sono membership attive. |
16.12 Diagnostica messaggi STID
| Messaggio | Significato e azione |
|---|---|
stid_route_member_updated: idle, no-op |
STidEnabled è vuoto o 0. Comportamento normale: il member non è gestito da STID. |
stid_handle_request: no validity source, resetting STidEnabled to 0 |
Il member non ha né membership attive né booking futuri. L’integrazione non emette la VCard. Soluzione: assegnare prima una membership al team. |
stid_create_premium_vcard: VCard created |
Emissione riuscita. Il messaggio riporta l’UUID. |
stid_handle_request: reused revoked VCard |
Il member aveva una VCard revocata, è stata riattivata senza consumare crediti. |
stid_handle_revoke: already revoked, no-op |
STidEnabled = -2 ma la VCard era già revocata su STID. Nessuna azione. |
today.inc: STID credit balance low |
Il saldo crediti STID è sotto soglia (default 20). Acquistare nuovi crediti. |
stid_bridge: ... HTTP 401 / 403 |
Problema di autenticazione STID. Verificare credenziali in set_ornd1.inc. |
Card ... can't be revoked because it has status Sent |
Si è tentato di revocare una VCard mai attivata dall’utente. Il portale STID consente di cancellarla, non di revocarla. |
stid_handle_request: code propagated to APLUS |
Codice STID (PrivateId) registrato anche su APLUS via AddCodeToUser. Comportamento normale. Vedi 16.6-bis. |
stid_handle_request: failed to propagate code to APLUS |
Il codice STID non è stato registrato su APLUS. La VCard STID resta valida; ma il lettore APLUS non riconoscerà l’utente finché il codice non viene propagato. Vedi caso N. |
stid_handle_request: skipping APLUS code propagation |
Il member non ha aplusId valido oppure STID non ha restituito un PrivateId. Verificare prima la creazione utente APLUS (vedi 5.3). |
stid_generate_private_id: failed to obtain expected length after retries |
STID non ha restituito un PrivateId di lunghezza 10 nei 5 tentativi. Probabile cambio della reader configuration STID; segnalare al team tecnico. |
16.13 Casi pratici STID (cookbook)
Caso I — Nuovo collaboratore che deve accedere tramite app STID
- Su ORnD: creare il member nella company corretta, assicurarsi che la company abbia una membership attiva.
- Aggiungere la property
STidEnabled = -1sul member. - Attendere qualche secondo: l’email di invito arriva al member e
STidEnabledsu ORnD contiene ora un UUID. - Comunicare al member di installare l’app STID Mobile ID e attivare la VCard cliccando il link nell’email.
Caso J — Cessazione di un collaboratore con VCard attiva
- Su ORnD: aprire il member.
- Impostare
STidEnabled = -2. - Salvare. Charon revoca la VCard su STID; l’app del member smetterà di funzionare ai varchi.
Caso K — Cancellazione completa del member
- Cancellare il member da ORnD.
- Charon cancella la VCard su STID; non è necessaria alcuna azione manuale lato STID.
Caso L — Member che non riceve l’email di invito STID
- Verificare che
STidEnabledsu ORnD contenga effettivamente un UUID (non resti-1). - Se contiene
-1o0, vuol dire che la creazione è fallita: cercare nei log il messaggiostid_handle_request: no validity sourceo un errore HTTP STID. - Se contiene un UUID ma l’email non è arrivata: verificare la cartella spam del member; in alternativa il team tecnico può rilanciare l’invito dal portale STID.
Caso N — La VCard STID c’è ma il lettore APLUS non riconosce l’utente
- Probabile causa: la propagazione del codice STID → APLUS è fallita. Cercare nei log
stid_handle_request: failed to propagate code to APLUSper il member in questione. - Verificare che il member abbia
aplusIdvalido su ORnD; se manca, vedi caso C. - Quando il member ha
aplusIdvalido, impostare di nuovoSTidEnabled = -1per rieseguire il flusso completo (questo riemetterà una nuova VCard, consumando 5 crediti). In alternativa il team tecnico può richiamare manualmenteAddCodeToUserlato APLUS.
Caso M — Estensione della validità di una VCard quando si rinnova una membership
- Su ORnD: rinnovare la membership del team (allungare
endDate). - Charon riceve il webhook
membership.updated, ricalcola la data fine VCard, e aggiorna automaticamente STID con la nuova scadenza. - Nessuna azione manuale sul member.
16.14 Cosa NON va fatto
- Non modificare manualmente l’UUID contenuto in
STidEnabled: il valore è scritto da Charon a partire dalla risposta di STID. Cambiarlo manualmente crea un disallineamento tra ORnD e STID che porta a Charon a non riconoscere più la VCard. - Non impostare
STidEnableda valori arbitrari diversi da-1,-2,0o un UUID legittimo. - Non revocare/cancellare manualmente la VCard dal portale STID se il member è ancora attivo su ORnD: alla prossima sincronizzazione il sistema potrebbe ricrearla.
16.15 Glossario marcatori STID
| Marcatore | Posizione | Effetto |
|---|---|---|
STidEnabled = -1 |
Member | Forza emissione VCard. |
STidEnabled = -2 |
Member | Forza revoca VCard attiva. Dopo revoca il campo torna vuoto. |
STidEnabled = 0 o vuoto |
Member | Member non ancora gestito da STID. Auto-emissione al primo booking (vedi 16.4). |
STidEnabled = <uuid 32 hex> |
Member | VCard emessa con quell’UUID (scritto da Charon, non modificare a mano). |
STidEnabled = -1 |
Company | Emissione massiva per i member del team senza UUID. Marker permanente: nuovi member ereditano l’emissione. |
STidEnabled = -2 |
Company | Revoca massiva per tutti i member del team con UUID. |
17. Manutenzione del manuale
⚠️ Importante per chi modifica il codice: ogni volta che si aggiunge una nuova funzionalità all’integrazione, si modifica una regola esistente o si introducono nuovi marcatori (valori speciali nelle proprietà), questo manuale va aggiornato in modo corrispondente. Aggiornare anche il numero di versione e la data in cima al documento.
Il file sorgente è charonlite/docs/manuale-operatore-integrazione-ORnD-APLUS.md. È un file Markdown editabile da qualunque editor; è il sorgente master del manuale.
Fine documento.