CoolCMS API

InvoiceNumberGenerator
in package

FinalYes

Generates an invoice number from a billing line (`BillingLine`).

Called by InvoiceManager::beforeSave() on INSERT of an invoice without a manually entered number. From the line it derives:

  • periodKey: sequence period key by the line billing_period (see resolvePeriodKey()),
  • order: sequence number within (line, period) = max(order) + 1,
  • number: line mask with %Y/%m/%d (from the issue date) and %number (zero-padded to number_length),
  • variableSymbol: digits of the number only, unless the VS was entered manually.

IMPORTANT: the critical section is serialized by SELECT ... FOR UPDATE on the billing line row (an existing row is a reliable lock across transactions, held until the save transaction ends). The schema backstop is UNIQUE(billing_line_id, order, period_key); a duplicate key would fail the transaction, the lock prevents it. The generator runs inside the already open save transaction (SaveTrait::save() begins it before beforeSave; TransactionManager shares the same EntityManagerInterface).

IMPORTANT: raw DBAL on purpose. It never touches the Doctrine identity map (no manager->find()/findAll()): those end in GetAllTrait::clearDoctrine(), which detaches the freshly hydrated invoice object graph before flush and loses it. The line and max(order) are therefore read through getConnection() only.

Table of Contents

Constants

BILLING_LINE_TABLE  : string = 'cms_mod_invoicer_billing_lines'
INVOICE_TABLE  : string = 'cms_mod_invoicer_invoices'

Properties

$em  : EntityManagerInterface

Methods

__construct()  : mixed
generate()  : bool
Generates and sets `order`, `periodKey`, `number` (and fills `variableSymbol`) on the invoice.
numberExists()  : bool
Tells whether an invoice with this number already exists.
buildNumber()  : string
Builds the invoice number from the line mask: date placeholders (`%Y`/`%m`/`%d`) from the issue date, `%number` = sequence number zero-padded to `numberLength`.
deriveVariableSymbol()  : string|null
Derives the variable symbol: digits of the invoice number only (the mask may carry a prefix or separators, a VS is purely numeric). An empty result gives null (the VS stays empty).
resolvePeriodKey()  : string
Returns the period key of the number sequence by the line period: - `never` gives `''` (one endless sequence), - `year` gives `'2026'`, - `month` gives `'2026-07'`, - `day` gives `'2026-07-06'`.

Constants

Properties

Methods

__construct()

public __construct(EntityManagerInterface $em) : mixed
Parameters
$em : EntityManagerInterface

generate()

Generates and sets `order`, `periodKey`, `number` (and fills `variableSymbol`) on the invoice.

public generate(Invoice $invoice) : bool

Returns false when the line does not exist (it vanished between the form selection and saving); the caller (InvoiceManager::beforeSave()) then fails the save with an error instead of storing a silent invoice without a number. Without a line the generator is not called at all (the manager rejects it earlier).

Parameters
$invoice : Invoice
Return values
bool

numberExists()

Tells whether an invoice with this number already exists.

public numberExists(string $number[, int|null $excludeInvoiceId = null ]) : bool

number has no unique index (the only unique one is the sequence uq_invoice_sequence on order/period_key/line), so the application guards duplicates: InvoiceManager::beforeSave() rejects an insert with an existing manual number and a generated number colliding with a manual import. Raw DBAL for the same reason as generate().

Parameters
$number : string
$excludeInvoiceId : int|null = null
Return values
bool

buildNumber()

Builds the invoice number from the line mask: date placeholders (`%Y`/`%m`/`%d`) from the issue date, `%number` = sequence number zero-padded to `numberLength`.

private buildNumber(string $mask, DateTime $issuedAt, int $order, int $numberLength) : string
Parameters
$mask : string
$issuedAt : DateTime
$order : int
$numberLength : int
Return values
string

deriveVariableSymbol()

Derives the variable symbol: digits of the invoice number only (the mask may carry a prefix or separators, a VS is purely numeric). An empty result gives null (the VS stays empty).

private deriveVariableSymbol(string $number) : string|null
Parameters
$number : string
Return values
string|null

resolvePeriodKey()

Returns the period key of the number sequence by the line period: - `never` gives `''` (one endless sequence), - `year` gives `'2026'`, - `month` gives `'2026-07'`, - `day` gives `'2026-07-06'`.

private resolvePeriodKey(string $billingPeriod, DateTime $issuedAt) : string
Parameters
$billingPeriod : string
$issuedAt : DateTime
Return values
string
On this page

Search results