XScript Manual · Chapter 51

SN Object — Serial Number Rules

The script keyword SN provides serial-number rules for label printing, MES reporting, and tracing. Each rule combines a fixed zone (Lot/Line) and a variable zone (sequence) and can be registered, generated, and managed by name.

ConceptMeaning
RuleIdentified by name. Multiple rules can run in the same project
Format[fixedWidth:type:align]&[field::length]|[variable] — e.g. `[12:0:Left]&[Lot::6]
Context4 keys: LotNo · LineNo · WorkOrderNo · SubLot
Excluded charsDefault "1,0,D,I,O" (visually ambiguous chars excluded)

One-line summarySN.RegisterRule(...) to register → SN.SetContext(...) to fill the lot → SN.GenerateNext(...) to issue.


1) Register / update a rule

Register with a name and a full format string in one line.

// Direct full format
SN.RegisterRule("prodA", "[12:0:Left]&[Lot::6]|[SN:SequencialDecimal:0:6]");
 
// Verify registration
if( SN.GetRule("prodA") == null )
{
    LogError("rule register failed");
    return false;
}

If a rule with the same name already exists, it is overwritten — and the existing sequence counter is not preserved.


2) Fill the context

External values that will be merged into the serial:

SN.SetContext("prodA", "LotNo",       "LOT2026");
SN.SetContext("prodA", "LineNo",      "L1");
SN.SetContext("prodA", "WorkOrderNo", "WO001");
SN.SetContext("prodA", "SubLot",      "S01");

Valid keys: "LotNo", "SubLot", "LineNo", "WorkOrderNo" (other keys return false).


3) Generate the next serial

string sn = SN.GenerateNext("prodA");
if( sn == "" )
{
    LogError("generate next failed");
    return false;
}
Log($"new SN : {sn}");
// e.g. "12LOT2026000001"

GenerateNext increments the sequence counter by 1 and returns the new value.

Peek without incrementing

string current = SN.Peek("prodA");   // last variable-zone value

Reset the counter

SN.ResetSequence("prodA");           // keep rule definition, reset variable zone

4) Preview / batch

Preview — no state change

// 5 sample serials for a label designer / review screen (counter is NOT advanced)
string[] samples = SN.Preview("prodA", 5);

GenerateBatch — counter advances

// Issue 100 labels at once for a printer
string[] batch;
if( SN.GenerateBatch("prodA", 100, batch) == false )
{
    LogError("batch failed");
    return false;
}
for(i, 0, batch.Length - 1)
{
    PRINTER.PrintLabel(batch[i]);
}

5) Excluded characters

Comma-separated list of characters never used in the variable zone.

// Default (when not set) : "1,0,D,I,O"
string current = SN.GetExcludedChars("prodA");
Log($"excluded : {current}");
 
// Update
SN.SetExcludedChars("prodA", "1,0,O");
 
// No exclusion
SN.SetExcludedChars("prodA", "");

Excluding characters that look like 0/1 (I/O) drastically reduces print/OCR misreads.


6) List / remove

// All registered rule names
string[] names = SN.GetRuleNames();
for(i, 0, names.Length - 1) Log(names[i]);
 
// Single remove
SN.RemoveRule("prodA");

7) Persistence — file / project

Rule definitions serialize to JSON. The variable-zone counter is NOT persisted — it lives in memory while the system runs.

// File
SN.SaveToFile("D:/Backup/rules.json");
SN.LoadFromFile("D:/Backup/rules.json");
 
// Default project path (SerialRules.XDF)
SN.SaveToProject();
SN.LoadFromProject();

LoadFromXxx clears the manager first and refills it. Export beforehand if you need to preserve existing rules.


Common patterns

On lot start — register lot, issue first serial

FUNCTION OnLotStart(string lotNo, string subLot)
{
    SN.SetContext("prodA", "LotNo",  lotNo);
    SN.SetContext("prodA", "SubLot", subLot);
    SN.ResetSequence("prodA");      // start counter on a new lot
 
    string firstSn = SN.GenerateNext("prodA");
    Data::CurrentSN = firstSn;
    return true;
}

Auto-register on first project boot

FUNCTION OnInit()
{
    if( SN.LoadFromProject() == false )
    {
        // no file yet — register defaults and save
        SN.RegisterRule("prodA", "[12:0:Left]&[Lot::6]|[SN:SequencialDecimal:0:6]");
        SN.SetExcludedChars("prodA", "1,0,D,I,O");
        SN.SaveToProject();
    }
    return true;
}

Preview → confirm → real issue

string[] sample = SN.Preview("prodA", 3);
string msg = $"Sample: {sample[0]} / {sample[1]} / {sample[2]}\nProceed?";
if( ShowMessage(EB_YesNo, 0, msg) == ER_Yes )
{
    string real = SN.GenerateNext("prodA");
    // ... print or report
}

Quick reference

GroupFunctions
Register / lookupRegisterRule(name, fullFormat) · GetRule(name) · GetRuleNames() · RemoveRule(name)
ContextSetContext(name, key, value) (LotNo/SubLot/LineNo/WorkOrderNo)
Excluded charsSetExcludedChars(name, chars) · GetExcludedChars(name)
IssueGenerateNext(name) · Peek(name) · ResetSequence(name) · Preview(name, count) · GenerateBatch(name, count, ref array)
PersistenceSaveToFile(path) · LoadFromFile(path) · SaveToProject() · LoadFromProject()