Passa al contenuto principale

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+2 senza mancanze dentro ciascuna sequenza

Se i buchi sono accettabili, un auto field testuale come INV-{id:lpad(5, '0')} è più semplice.

Modello dati​

OggettoCampi chiave
Invoice (esempio)number (Number, Unique da solo), più i tuoi campi di business

Oppure, per ripartire ogni anno (o altra sezione):

OggettoCampi chiave
Invoiceyear (Text o Number), number (Number) — entrambi Unique insieme

Il gruppo di unicità è la chiave della sequenza:

  • number unique da solo → una sequenza per tutto l'oggetto
  • number unique con year (o branch, …) → una sequenza per valore partner

Vedi Unicità. Non creare un oggetto Counter separato per le app nuove.

Passaggi​

  1. Su Invoice, aggiungi il campo Number number e abilita Unique (da solo, o insieme a year / altri campi chiave).
  2. Tieni number (e i partner come year) in sola lettura sul form di creazione.
  3. Opzionalmente deriva un'etichetta pubblica con un auto field testuale, ad esempio {year}/{number} o INV-{year}-{number:lpad(5, '0')}.
  4. 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.

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​

EsigenzaGruppo di unicità
Una sequenza che non riparte mainumber unique da solo
Riparte ogni anno solareUnique su number + year (FORMAT(invoice_date, 'Y') o FORMAT(NOW(), 'Y'))
Anno fiscale (es. apr–mar)Unique su number + campo anno fiscale
Per filiale / sedeUnique 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)​

OggettoCampi chiave
Counter (global)number (Number) — ultimo valore emesso
Invoicenumber (Number), più campi di business
  1. Crea Counter globale con Number number (default 0); opzionalmente imposta il valore iniziale.
  2. In creazione, Aggiorna Counter impostando number a {number}+1, poi Aggiorna questo record e imposta Invoice number dal Counter.

Sequenze per anno (YearlyCounter)​

OggettoCampi chiave
YearlyCounter (non globale)year (Unique), number
Invoiceyear, number (unique insieme)
  1. Crea YearlyCounter per l'anno (number ← 0); lo year unique riusa la riga se esiste già.
  2. Aggiorna quel YearlyCounter: number ← {number}+1.
  3. Aggiorna questo record: timbra year e number dal 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 separati id interno e number di 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.