Contatori sequenziali senza buchi
Assegna una sequenza leggibile — numeri di fattura, codici ticket, ID di protocollo — che resti contigua. Alloca i numeri tu, non dall'id auto-generato del record.
Preferisci l'azione nativa di sequenza su un campo Number univoco. Bobuild mantiene un contatore interno per chiave, lo blocca nella stessa transazione del salvataggio e non riusa un numero dopo un rollback o dopo che elimini una riga di business.
Perché non usare {id}?
Ogni record riceve un id sequenziale assegnato automaticamente. Va bene per i collegamenti interni e per codici come P{id}, ma la sequenza può lasciare buchi: create annullate, submit falliti dopo che l'id era già riservato, bozze eliminate e casi simili saltano dei numeri. Quando regole fiscali o operative richiedono nessun buco, alloca un number di business separato.
Quando usarlo
- Numeri di fattura / ricevuta che devono essere contigui
- Numeri di protocollo o pratica senza valori saltati
- Numeri che ripartono ogni anno (o per filiale, tipo documento, …)
- Qualsiasi contatore pubblico in cui gli auditor si aspettano
n,n+1,n+2senza mancanze dentro ciascuna sequenza
Se i buchi sono accettabili, un auto field testuale come INV-{id:lpad(5, '0')} è più semplice.
Sequenza nativa (consigliata)
Modello dati
| Oggetto | Campi chiave |
|---|---|
| Invoice (esempio) | number (Number, Unique da solo), più i tuoi campi di business |
Oppure, per ripartire ogni anno (o altra sezione):
| Oggetto | Campi chiave |
|---|---|
| Invoice | year (Text o Number), number (Number) — entrambi Unique insieme |
Il gruppo di unicità è la chiave della sequenza:
numberunique da solo → una sequenza per tutto l'oggettonumberunique conyear(obranch, …) → una sequenza per valore partner
Vedi Unicità. Non creare un oggetto Counter separato per le app nuove.
Passaggi
- Su Invoice, aggiungi il campo Number
numbere abilita Unique (da solo, o insieme ayear/ altri campi chiave). - Tieni
number(e i partner comeyear) in sola lettura sul form di creazione. - Opzionalmente deriva un'etichetta pubblica con un auto field testuale, ad esempio
{year}/{number}oINV-{year}-{number:lpad(5, '0')}. - Sul form di creazione (o sul task di create API), aggiungi un'azione Aggiorna questo record (o includi i campi in un Crea) che imposta:
- ogni partner di chiave (
year, …) — costante, formula o copia dal form; number→ al prossimo valore di sequenza.
- ogni partner di chiave (
I campi partner devono essere impostati nella stessa azione (o già presenti sulla riga in caso di update). I task del form corrono nella stessa transazione del salvataggio: le create concorrenti si serializzano sul contatore interno corrispondente e i rollback non consumano numeri.
Il primo valore emesso è 1. Chiavi di unicità diverse (ad esempio 2026 vs 2027) hanno sequenze indipendenti.
Scelta della chiave
| Esigenza | Gruppo di unicità |
|---|---|
| Una sequenza che non riparte mai | number unique da solo |
| Riparte ogni anno solare | Unique su number + year (FORMAT(invoice_date, 'Y') o FORMAT(NOW(), 'Y')) |
| Anno fiscale (es. apr–mar) | Unique su number + campo anno fiscale |
| Per filiale / sede | Unique su number + branch (o branch + year) |
| Più serie (fatture vs note di credito) | Unique su number + Text key come CONCAT(..., '-INV') |
Contatori manuali (legacy)
Prima dell'azione nativa, lo stesso comportamento si costruiva con un oggetto Counter (o YearlyCounter) esplicito e due passi di task: incrementa il contatore, poi timbra la fattura. Continua a funzionare se lo usi già; per le app nuove preferisci la sequenza nativa sopra.
Una sequenza (contatore globale)
| Oggetto | Campi chiave |
|---|---|
| Counter (global) | number (Number) — ultimo valore emesso |
| Invoice | number (Number), più campi di business |
- Crea Counter globale con Number
number(default0); opzionalmente imposta il valore iniziale. - In creazione, Aggiorna Counter impostando
numbera{number}+1, poi Aggiorna questo record e imposta Invoicenumberdal Counter.
Sequenze per anno (YearlyCounter)
| Oggetto | Campi chiave |
|---|---|
| YearlyCounter (non globale) | year (Unique), number |
| Invoice | year, number (unique insieme) |
- Crea YearlyCounter per l'anno (
number←0); loyearunique riusa la riga se esiste già. - Aggiorna quel YearlyCounter:
number←{number}+1. - Aggiorna questo record: timbra
yearenumberdal contatore.
Consigli
- Preferisci al prossimo valore di sequenza su un Number unique piuttosto che mantenere un oggetto Counter visibile.
- Non riusare l'auto field
{id}per la stessa sequenza pubblica — tieni separatiidinterno enumberdi business. - Eliminare una riga di business non libera il suo numero per il riuso (comportamento adatto al fiscale).
- Gli stessi pattern funzionano sugli endpoint API Create quando i record nascono fuori dall'UI.
Correlati
- Unicità — chiave di sequenza = gruppo di unicità
- Operazioni sui record — create, update, azioni sui campi
- Task dei form
- Oggetti globali — solo per il pattern Counter legacy
- Auto fields — quando bastano codici basati su
{id} - Placeholder e funzioni —
FORMAT,NOW,CONCAT