CoolCMS API

DecimalQuantityGuardTrait

Rejects fractional item quantities while the `quantity` column is still an integer.

Covers the deploy window where the code is new but the column has not been altered to decimal(8,2) yet. In that window a fractional quantity would pass without an error and be stored rounded (the database does not reliably reject it; depending on sql_mode '2.50' may silently become 3). Totals are recomputed from the stored quantity on every save (InvoiceCalculator), so the invoice would silently grow on any re-save (0.50 becomes 1: the line doubles).

The guard is hard and sits in beforeSave() of both managers, the point every invoice write passes through (admin form via the bridge, Api endpoint, InvoiceComposer, checkout and payment generators). The rejection is VALIDATION_FAILED, so SaveTrait rolls the whole operation back and no half-saved document remains.

It switches itself off: once the column is altered, information_schema reports decimal and everything passes. The column type is cached statically for one request, and the probe runs only when a fractional quantity is actually found, so a normal integer invoice costs no extra query.

Table of Contents

Constants

TABLE_INVOICE_ITEMS  : string = 'cms_mod_invoicer_invoice_items'
Tables whose `quantity` becomes `decimal(8,2)` (elsewhere it stays an integer piece count).
TABLE_INVOICE_TEMPLATE_ITEMS  : string = 'cms_mod_invoicer_invoice_template_items'

Properties

$decimalQuantityColumns  : array<string, bool>
Whether `quantity` is a decimal column, per table. Valid for this request only (the schema does not change during a request; the alter is a maintenance step between requests).

Methods

findFractionalQuantity()  : string|null
Returns the first fractional quantity in the collection, or `null`. Compared with `fmod()`, not by string shape: the setter also receives `int`/`float`, and after hydration the getter returns the database spelling, which may differ ('2.5' vs '2.50').
guardFractionalQuantity()  : Result|null
Rejects the write when a line has a fractional quantity and the column is still an integer.
hasDecimalQuantityColumn()  : bool
Tells whether `quantity` of the table is already `decimal`; unknown counts as no (rejecting is safer).

Constants

TABLE_INVOICE_ITEMS

Tables whose `quantity` becomes `decimal(8,2)` (elsewhere it stays an integer piece count).

protected string TABLE_INVOICE_ITEMS = 'cms_mod_invoicer_invoice_items'

TABLE_INVOICE_TEMPLATE_ITEMS

protected string TABLE_INVOICE_TEMPLATE_ITEMS = 'cms_mod_invoicer_invoice_template_items'

Properties

$decimalQuantityColumns

Whether `quantity` is a decimal column, per table. Valid for this request only (the schema does not change during a request; the alter is a maintenance step between requests).

private static array<string, bool> $decimalQuantityColumns = []

Methods

findFractionalQuantity()

Returns the first fractional quantity in the collection, or `null`. Compared with `fmod()`, not by string shape: the setter also receives `int`/`float`, and after hydration the getter returns the database spelling, which may differ ('2.5' vs '2.50').

private findFractionalQuantity(iterable<string|int, mixed> $lines) : string|null
Parameters
$lines : iterable<string|int, mixed>
Return values
string|null

guardFractionalQuantity()

Rejects the write when a line has a fractional quantity and the column is still an integer.

private guardFractionalQuantity(Connection $connection, string $table, iterable<string|int, mixed> $lines) : Result|null

Returns null when all is well (all quantities whole, or the column already altered).

Parameters
$connection : Connection
$table : string
$lines : iterable<string|int, mixed>

item lines of the invoice or template

Return values
Result|null

hasDecimalQuantityColumn()

Tells whether `quantity` of the table is already `decimal`; unknown counts as no (rejecting is safer).

private hasDecimalQuantityColumn(Connection $connection, string $table) : bool
Parameters
$connection : Connection
$table : string
Return values
bool
On this page

Search results