S60 — ERP Model Alignment (iDempiere BOM Pattern)¶
Foundation: BBC §1 · ConstructionAsERP §1
Principles¶
- ONE C_DocType: "Construction Order" — metadata only, not a compilation driver
- No M_BomCategory — use M_Product_Category instead (product IS its category)
- Products with IsBOM=Y ARE BOMs — no separate bom_type hierarchy
- Compiler walks C_OrderLine tree, not m_bom directly
- YAML is the test script (creates C_Order + OrderLines), not a pipeline driver
Schema Gaps (UI session review)¶
| ID | Table | Column/Feature | Status |
|---|---|---|---|
| U2 | C_OrderLine | Discipline TEXT DEFAULT 'ARC' |
DONE (S60_schema.sql) |
| U3 | C_Order | Jurisdiction TEXT |
DONE (S60_schema.sql) |
| U4 | C_Order | OccupancyClass TEXT |
DONE (S60_schema.sql) |
| U5 | ~~DAO~~ | ~~OrderLineHydrationDAO~~ | SUPERSEDED — OrderLineWalker + bom_child_id join-back IS the bridge |
| U6 | Table+DAO | AD_Val_Rule_Exception |
Table DONE; wiring TODO |
Code Changes¶
| # | Change | Status |
|---|---|---|
| 1 | Schema migration (U2-U4, U6) | DONE — S60_schema.sql |
| 2 | Compiler walks C_OrderLine tree (BomDropper + OrderLineWalker) | DONE — BomDropper.java, OrderLineWalker.java |
| 3 | BuildingRegistryTest → bomDrop per building | DONE |
| 4 | run_RosettaStones.sh → same path (schema auto-applied) | DONE |
| 5 | C_DocType as metadata only (not compilation driver) | DONE — PlacementLoader reads C_OrderLine when available |
| 6 | Replace M_BomCategory references with M_Product_Category | ASSESSED — see §M_BomCategory Assessment below |
| 7 | ~~OrderLineHydrationDAO~~ | SUPERSEDED by OrderLineWalker |
| 8 | Wire AD_Val_Rule validation with exception override | DONE — X_AD_Val_Rule_Exception + MValRuleException DAO |
| 9 | Visual diff report: per-element TSV under --diff flag |
DONE — SpatialDiff.toTsv(), --diff flag on run_RosettaStones.sh |
| 10 | Script accepts building prefixes as arguments | TODO |
Proven¶
WorkOrderCompileTest(W-WO-1: bomDrop → compile → 60 elements)BomDropConfigureTest(TC-4: roof swap → 95 elements)- S60 Rosetta Stone: SH (55), FK (82), DM (60) all GREEN through OrderLine path
Component Library Setup¶
IFC Sources¶
| Source | Building | Download |
|---|---|---|
| buildingSMART samples | SampleHouse, Duplex | https://github.com/buildingSMART/Sample-Test-Files |
| KIT ifcwiki (Karlsruhe) | FZKHaus | https://www.ifcwiki.org/index.php?title=KIT_IFC_Examples |
| opensourceBIM | AC11 Institute | https://github.com/opensourceBIM |
| SJTII Terminal (Malaysia) | Terminal (7 discipline IFCs) | Local: DAGCompiler/lib/input/IFC/SJTII-*.ifc |
| PCERT Infrastructure | Bridge, Road, Rail (IFC4X3) | Local: DAGCompiler/lib/input/IFC/PCERT_Infra_*.ifc |
| DemoHouse | Generative (no IFC source) | Created by migration/seed_dm_bom.sql |
All IFC files stored in DAGCompiler/lib/input/IFC/. 34 extracted + 1 generative = 35 buildings.
The Formula¶
IFC files (DAGCompiler/lib/input/IFC/*.ifc)
↓ tools/extract.py (ifcopenshell)
Extracted reference DBs (DAGCompiler/lib/input/*_extracted.db)
↓ classify_*.yaml (IFCtoBOM/src/main/resources/) — ONLY human invention point
run_RosettaStones.sh
├─ [populate] IFCtoBOMMain --populate
│ ├─ ExtractionPopulator → read reference DB, extract elements
│ ├─ ProductRegistrar.ensureProductCatalog() → M_Product (2472 products)
│ ├─ ExtractionPopulator.fillGeometryGaps() → I_Geometry_Map (167K mesh entries, 358MB blobs)
│ └─ ProductRegistrar.ensureProductImages() → M_Product_Image (2472 links)
│
└─ [IFCtoBOM pipeline] IFCtoBOMMain --classify
├─ Build m_bom + m_bom_line (tack offsets, verb refs)
├─ Write {PREFIX}_BOM.db
└─ [DAGCompiler] BomDropper → OrderLineWalker → compile → output.db
Scripts¶
| Script | Purpose |
|---|---|
scripts/onboard_ifc.sh |
Full 8-step onboarding for new buildings |
scripts/run_RosettaStones.sh |
Master orchestrator (populate + compile + gate) |
tools/extract.py |
IFC → extracted.db (ifcopenshell) |
Key Java Entry Points¶
| Class | Purpose |
|---|---|
IFCtoBOM/.../IFCtoBOMMain.java |
CLI: --populate and --classify |
IFCtoBOM/.../ExtractionPopulator.java |
Element extraction + geometry gap fill |
IFCtoBOM/.../ProductRegistrar.java |
M_Product catalog + M_Product_Image links |
IFCtoBOM/.../IFCtoBOMPipeline.java |
11-stage pipeline orchestrator |
Database Size¶
component_library.db: 433MB total (358MB geometry blobs). Too large for git — schema changes go to migration/, pristine binary committed only when finished.
Database Backup¶
backup/db_snapshot_20260323_014819/ (1.5GB — library, output, input DBs).
WARNING: backup/ is .gitignored. NEVER commit database snapshots to git — GitHub rejects files >100MB. The backup dir stays local-only.
R21 Implementation (host_element_ref)¶
IFC chain: Wall ←(IfcRelVoidsElement)← IfcOpeningElement ←(IfcRelFillsElement)← Door/Window.
Data flow:
1. tools/extract.py extracts chain → rel_fills_host(element_guid, host_guid) table in reference DB
2. DAGCompiler/python/reference_schema.sql defines the table
3. ExtractionPopulator.readFillsHost() reads the table (backward-compat: empty map if table absent)
4. ExtractionPopulator.deriveRows() resolves host GUID → host element_ref via GUID→elementRef map
5. ExtractionReader.ExtractionElement.hostElementRef() carries the value
6. All BOM builders + VerbFactorizer write host_element_ref to m_bom_line
7. migration/R21_host_element_ref.sql adds the column to existing DBs
IMPORTANT: Reference DBs must be re-extracted with tools/extract.py to populate rel_fills_host. Pre-R21 reference DBs have no rel_fills_host table — ExtractionPopulator handles this gracefully (returns empty map).
Consumers: M16/M17 validation rules (DocValidate) can now use FK join on host_element_ref instead of AABB proximity. See LAST_MILE_PROBLEM.md §Check 9.
M_BomCategory Assessment (#6)¶
Finding (S60-S2): NOT a simple rename. M_BomCategory and M_Product_Category are orthogonal axes:
| Axis | M_BomCategory | M_Product_Category |
|---|---|---|
| Purpose | Room/zone template types | IFC discipline classification |
| Codes | LI, BD, KT, BT, DN, FR, ST... (19 codes) | STR, ARC, MEP, IFC_WALL... (tree) |
| Structure | Junction table (M_BomCategoryLine) | Self-referencing (Parent_Category_ID) |
| Used by | Template grammar, BIM_COBOL verbs | Discipline assignment, product catalog |
Impact: 77 files across 6 layers (PO, BIM_COBOL verbs, pipeline, tests, DAOs, migrations).
What works already: DisciplineBomBuilder uses discipline codes (ARC/STR/FP) as bom_category — these ARE M_Product_Category root IDs. The CO path is already aligned.
What needs dedicated session: - BIM_COBOL verbs: DEFINE CATEGORY, ADD TEMPLATE RULE, REGISTER BOM (3 files) - Template grammar: M_BomCategoryLine → M_Product_Category self-referencing tree - AABB template matching: currently on M_BomCategory, needs PlacementContext - 10+ test files need verb/query refactoring - Schema migration: backfill 19 functional codes → M_Product_Category entries