Skip to content

Sequences

Sequences provide automatic document numbering across all modules. They generate sequential, formatted identifiers for journal entries, invoices, purchase orders, and any other document type. Each sequence defines a prefix, suffix, digit padding, and reset frequency. Counters are tracked in a separate table supporting per-branch and fiscal-period auto-reset.

Purpose

  • Auto-generate unique, sequential document numbers
  • Support configurable formats with prefix, suffix, year/month inclusion, and zero-padding
  • Allow per-branch numbering for organizations that need branch-specific sequences
  • Enable periodic reset (never, yearly, monthly) for numbering schemes
  • Maintain separate counter rows per branch and fiscal period

Entity Attributes

Sequence (Definition)

FieldTypeDescription
idintegerPrimary key
company_idintegerForeign key to the company
namestringSequence name (English)
name_arstringSequence name (Arabic)
modulestringTarget module (e.g., accounting, sales)
entitystringTarget entity (e.g., journal_entry, invoice)
prefixstring?Text prepended to the number (e.g., JV-, INV-)
suffixstring?Text appended to the number
include_yearbooleanWhether to include the year in the generated number
include_monthbooleanWhether to include the month in the generated number
digitsintegerNumber of digits for zero-padding (e.g., 5 produces 00001)
reset_frequencyenumWhen to reset the counter: never, yearly, monthly
per_branchbooleanWhether numbering is separate per branch
is_activebooleanWhether the sequence is active
created_atdatetimeCreation timestamp
updated_atdatetimeLast update timestamp
deleted_atdatetime?Soft-delete timestamp

Sequence Counter

Counters track the current number for each combination of sequence, branch, and fiscal period.

FieldTypeDescription
idintegerPrimary key
sequence_idintegerFK to sequences
branch_idintegerBranch ID (0 = all branches)
fiscal_yearintegerFiscal year (0 = no yearly reset)
fiscal_monthintegerFiscal month (0 = no monthly reset)
last_numberbigintLast number issued
created_atdatetimeCreation timestamp
updated_atdatetimeLast update timestamp

Unique constraint: (sequence_id, branch_id, fiscal_year, fiscal_month)

Generated Number Examples

Given a sequence with prefix: "JV-", include_year: true, digits: 5, counter at last_number: 42:

SettingGenerated Number
Year onlyJV-2026-00042
Year + MonthJV-2026-02-00042
No year, with suffix -KWJV-00042-KW
Minimal (no prefix/suffix/year)00042

Default Sequences

14 default sequences are seeded during installation:

ModuleEntityPrefixResetPer Branch
corepartnerBP-neverno
coreproductPRD-neverno
salesquotationQT-yearlyno
salessales_orderSO-yearlyno
salesinvoiceINV-yearlyyes
salesreturnSR-yearlyno
salescredit_noteCN-yearlyno
salesreceipt_voucherRV-yearlyyes
purchasespurchase_orderPO-yearlyno
purchasesbillBILL-yearlyno
purchasespayment_voucherPV-yearlyyes
accountingjournal_entryJV-yearlyno
inventorystock_movementSM-yearlyno
manufacturingproduction_orderMO-yearlyno

How Counters Work

When a number is generated:

  1. The system finds the active sequence for the requested module + entity
  2. Determines the branch: if per_branch is true and a branch ID is provided, uses that branch; otherwise uses 0 (all branches)
  3. Resolves the fiscal period: if reset_frequency = yearly, uses current year; if monthly, uses year + month; otherwise 0
  4. Finds or creates a counter row matching (sequence_id, branch_id, fiscal_year, fiscal_month)
  5. Locks the counter row, increments last_number, and saves
  6. Builds the formatted string from prefix + year + month + padded number + suffix

This means when a new fiscal year starts, a new counter row is automatically created starting from 1, effectively resetting the numbering.

Relationships

API Endpoints

MethodPathDescription
GET/api/core/sequencesList all sequences (paginated)
POST/api/core/sequencesCreate a new sequence
GET/api/core/sequences/{id}Get a specific sequence
PUT/api/core/sequences/{id}Update a sequence
DELETE/api/core/sequences/{id}Soft-delete a sequence

Internal Use

Number generation is handled internally by the SequenceService. There is no public API endpoint to generate a number -- it happens automatically when documents are created or posted (e.g., journal entries get their number on post, partners get their code on creation).

Request/Response Examples

GET /api/core/sequences

Retrieve a paginated list of sequences, ordered by module and entity.

bash
curl -X GET https://moon-erp.test/api/core/sequences \
  -H "Accept: application/json" \
  -H "Authorization: Bearer {token}"
dart
final response = await http.get(
  Uri.parse('https://moon-erp.test/api/core/sequences'),
  headers: {
    'Accept': 'application/json',
    'Authorization': 'Bearer $token',
  },
);

Response 200 OK

json
{
  "data": [
    {
      "id": 1,
      "name": "Journal Entry Sequence",
      "name_en": "Journal Entry Sequence",
      "name_ar": "تسلسل قيد اليومية",
      "module": "accounting",
      "entity": "journal_entry",
      "prefix": "JV-",
      "suffix": null,
      "include_year": true,
      "include_month": false,
      "digits": 5,
      "reset_frequency": "yearly",
      "per_branch": false,
      "is_active": true,
      "created_at": "2026-01-01T00:00:00.000000Z",
      "updated_at": "2026-01-01T00:00:00.000000Z"
    }
  ],
  "links": { "first": "...?page=1", "last": "...?page=1", "prev": null, "next": null },
  "meta": { "current_page": 1, "from": 1, "last_page": 1, "per_page": 25, "to": 1, "total": 1 }
}

POST /api/core/sequences

Create a new sequence.

bash
curl -X POST https://moon-erp.test/api/core/sequences \
  -H "Content-Type: application/json" \
  -H "Accept: application/json" \
  -H "Authorization: Bearer {token}" \
  -d '{
    "name": "Purchase Order Sequence",
    "name_ar": "تسلسل أمر الشراء",
    "module": "purchasing",
    "entity": "purchase_order",
    "prefix": "PO-",
    "suffix": null,
    "include_year": true,
    "include_month": false,
    "digits": 5,
    "reset_frequency": "yearly",
    "per_branch": false,
    "is_active": true
  }'
dart
final response = await http.post(
  Uri.parse('https://moon-erp.test/api/core/sequences'),
  headers: {
    'Content-Type': 'application/json',
    'Accept': 'application/json',
    'Authorization': 'Bearer $token',
  },
  body: jsonEncode({
    'name': 'Purchase Order Sequence',
    'name_ar': 'تسلسل أمر الشراء',
    'module': 'purchasing',
    'entity': 'purchase_order',
    'prefix': 'PO-',
    'include_year': true,
    'include_month': false,
    'digits': 5,
    'reset_frequency': 'yearly',
    'per_branch': false,
    'is_active': true,
  }),
);

Response 201 Created

json
{
  "data": {
    "id": 3,
    "name": "Purchase Order Sequence",
    "name_en": "Purchase Order Sequence",
    "name_ar": "تسلسل أمر الشراء",
    "module": "purchasing",
    "entity": "purchase_order",
    "prefix": "PO-",
    "suffix": null,
    "include_year": true,
    "include_month": false,
    "digits": 5,
    "reset_frequency": "yearly",
    "per_branch": false,
    "is_active": true,
    "created_at": "2026-02-16T10:00:00.000000Z",
    "updated_at": "2026-02-16T10:00:00.000000Z"
  }
}

Business Rules

  • Company scoping -- sequences are scoped to the authenticated user's company.
  • Module + Entity identification -- each sequence targets a specific module and entity combination (e.g., accounting / journal_entry).
  • Reset frequency -- controls when numbering resets:
    • never -- the counter increments indefinitely across all periods.
    • yearly -- a new counter starts at 1 for each fiscal year.
    • monthly -- a new counter starts at 1 for each month.
  • Per-branch numbering -- when per_branch is true, each branch maintains its own independent counter for the sequence.
  • Digits (padding) -- the digits field controls zero-padding. A value of 5 with counter at 42 produces 00042.
  • Active flag -- only active sequences (is_active: true) are used for number generation. Deactivating a sequence stops it from issuing new numbers.
  • Atomic locking -- counter rows are locked during increment to prevent duplicate numbers in concurrent requests.
  • Auto-creation -- counter rows are created on-demand when the first number is generated for a new branch/period combination.

Moon ERP API Documentation