The Bill of Quantities is the load-bearing screen of the entire estimating flow. Until v3.6, OpenConstructionERP capped BOQ depth at two levels — enough for a textbook example, not enough for a real tender package where Building › Substructure › Foundations › Strip footings › Concrete › C30/37 is a perfectly ordinary path. v3.6.0 lifts the cap to eight and makes the editor respect it end-to-end. v3.6.1 is the small follow-up that fixed the one rendering branch where depth > 2 still flattened to a list.
What changed
MAX_NESTING_DEPTH = 8
The validator and the FastAPI schema both moved to a single shared
constant MAX_NESTING_DEPTH = 8. Anything deeper raises a
structured 422 with the failing ordinal path included —
no more silent flattening when an import file went two levels past
the old cap.
Recursive parent_id tree walk
The BOQ editor now builds the visible tree by recursively walking
parent_id in a single query, instead of joining a fixed
number of levels. Ordinals (01.02.003.04) regenerate on
the way back up. The same walk powers totals roll-up and validation
rule scoping.
Resource-code dedup (#133)
Cost catalogues from different sources used to land duplicate
resource_code rows once a project imported from two
regional catalogues. v3.6.0 added a one-pass dedup keyed on
(catalogue_id, resource_code) with a deterministic
winner so re-imports stop growing the table.
v3.6.1 — the visible-tree fix
v3.6.0 stored the deeper rows correctly but one render path in
BoqGridContainer still trimmed at depth 2 because the
group-row builder used a static column join. v3.6.1 switched it to
the same recursive walk the service layer uses. Without it, deep rows
were invisible — with it, they expand cleanly.
Why it matters
Eight levels is not an arbitrary number. It is what a typical DIN 276 cost-group tree wants once you keep both the standard’s three-level hierarchy and the project-specific subdivision underneath it. Anything shallower forces estimators to either fold work-packages together (lossy) or store the structure in the description column (untyped). Neither plays well with downstream GAEB export or roll-up reporting.
The dedup pass closes related issue #133. Until v3.6.0 every re-import of the same catalogue created another copy of every row; after, the catalogue table is stable across re-imports and the unique constraint is enforced at write-time.
Upgrade
pip install --upgrade openconstructionerp==3.6.1
Alembic head moves to v3037. Existing two-level BOQs are
unchanged — the migration only adds index support for deeper trees.
No data backfill is required.
See the BOQ editor in action.
Live demo in your browser, or self-host in five minutes. AGPL-3.0, no signup required.