Skip to content

Bom editing plan

Make the assembly's BOM tab the place to read and edit its parts.
Start with inline add, remove, quantity changes, undo and BOM search.
Reuse the existing editor's backend and InvenTree's native BOM features.
Show units, shortages and material costs beside the parts they describe.
Preview KiCad changes and protect packaging and released instructions.
Ship the smallest useful version first, then add depth after a shop trial.

Status: proposal — requested by the owner on 2026-10-05; no implementation authorized here.

Recommendation: approve Phase 1, estimated 3–4 focused engineering days, including write-path safeguards and the UI gate. Keep advanced administration in InvenTree, reached from the assembly. Expand only after trying a real board BOM on a phone.

Owner decisions — proposed, not yet adopted

  1. Start with Phase 1 on one board assembly; choose the pilot (Robot Cow is suggested because its packing quantities are established).
  2. Keep native Can build and show a separate Packing readiness warning. Consumables remain consumables; do not silently change inventory allocation rules.
  3. Flag BOM changes after a released WI immediately. Recommend requiring Engineering review before a new build proceeds; decide whether to make that a hard interlock with the release-workflow work.
  4. Default costs to fitted materials plus consumables, with optional/DNP costs separate. Show the cost basis and unknowns; do not turn a partial subtotal into a complete total.

What is there today

Read-only inspection: /home/angel/assistant, HEAD 9025af0, 2026-10-05. These are source findings, not a live ERP or browser acceptance test.

  • static/app.js:894–895,952: Assemblies already opens #part/<pk>/bom, but its generic Parts columns omit BOM readiness; a list-level Edit BOM sends users to an assembly picker again.
  • app.js:1424–1447: assembly detail always offers Back to Parts. The BOM is a sortable miniTable; whole-row navigation competes with future editing. No BOM search, tree or edit controls live here.
  • The tab already shows reference, quantity, availability, can-build, substitutes and optional status. Availability/can-build use desktop-only columns; units, line notes and consumable badges are missing. Cost is on a separate tab.
  • app.js:679 embeds /bom in an iframe. static/bom.html contains the actual editor, including its inline script; partforms.js supplies shared helpers. The form is a long set of editable cards, separate from the assembly's context.
  • That editor already adds/removes lines and edits decimal quantity, references, note, optional, consumable and substitutes. It has Review → Apply → Undo, CSV import and New revision. These capabilities need relocation and refinement, not replacement.
  • Part search is separate from search within the BOM. Normal Add has no create-part shortcut; unmatched imported rows already offer /partnew?q=…. Removing a draft line lacks immediate per-line Undo.
  • objects.py:254–290 serves /app/api/part/{pk} from native BOM and requirements APIs. It drops editing metadata and substitute IDs. Reads stop at fixed limits; _side() converts errors into empty lists, risking a false “empty BOM.”
  • cost.py serves /app/api/cost/{pk} to Engineering/Admin; five-minute caching, recorded stock average, supplier fallback and sub-assembly rollup already exist. Current rows lack BOM IDs; costing uses the last build quantity, includes optional lines and lacks overage treatment.
  • minimums.py supplies /minimums/api/parts and preview/confirm/undo for minimums. Its usage calculation excludes optional and consumable lines; it is not a BOM editor or an authoritative shortage calculator.
  • actions.py supplies ERP HTTP methods and build previews; BOM mutations actually live in partforms.py. Build previews multiply BOM quantity by build quantity; do not mistake that simple warning calculation for full native availability semantics.

Reuse InvenTree, with version checks

Native InvenTree supports hierarchical BOMs, substitutes, optional/consumable lines, inherited variant lines, references, notes, import, comparison and validation. Its own UI switches the assembly BOM panel between viewing and editing. Reuse those records and operations. Native BOM guide

Native feature Proposed app treatment
Quantity, reference, note Inline fields; always show the part's units.
Optional Explicit choice; DNP import maps here under SOP-008.
Consumable Label “not allocated to builds”; show packing readiness separately.
Substitutes Qualified alternatives on the native BOM line.
Inherited Show source assembly; edit at the owning template.
Allow variants Advanced setting permitting variant stock; preserve existing value.
Overage/loss allowance Use the installed native fields and calculation.
Validation / import Native BOM checked status and import capabilities.

Current upstream schema exposes allow_variants, raw_amount, attrition, setup quantity and rounding multiple. Older versions used overage; upstream history records rounding differences. Inspect the installed version/schema before enabling controls. Preserve every native field through preview, copy, delete/restore and undo; the current adapter captures only a subset. Schema, overage history

Consumables are not allocated to build orders; optional lines need not be allocated. Substitute stock contributes to line availability. BOM validation uses a checksum and requires rechecking after relevant changes. Native validation is not document release. Native semantics

Useful editor patterns — borrow the interaction, keep our engine

  • InvenTree: edit on the assembly BOM panel, with import, substitutes and validation nearby. Keep an Open in InvenTree link for uncommon administration. UI guide
  • OpenBOM: single-level, indented and flattened views answer different questions. Start with top-level editing and expandable structure; flattened totals can follow. Views
  • Odoo MRP: its BOM Overview connects hierarchy with a chosen quantity, availability and costs. Put the target build quantity next to our shortages. Overview
  • Fusion / Altium: Fusion separates structured relations from aggregated parts; ActiveBOM places availability, cost and checks alongside line items. Use restrained status badges, with details on tap. Fusion model, ActiveBOM

The assembly page

Assemblies list → assembly → BOM is the normal path. Back restores the originating list/report, search and scroll. Remove the generic list-level Edit BOM action; retain New assembly. Existing edit links land on this BOM tab. Readiness/shortage summaries join the list in Phase 2 and share the Reports data contract.

Keep the assembly name/revision, BOM checked status, search and primary actions visible. Edit BOM enables editing in place; Add line opens part search. Match IPN/name/MPN, show units and identity, and offer Create new part through the existing part form with a return to this draft. Creation has its own preview/undo; cancelling a BOM draft does not delete the new part.

Quantity/reference/note edit beside the line. Advanced details contain optional, consumable and qualified substitutes. Use decimal quantities: 27 mm Brother tape, 0.7 mL coating, one Zebra bag label and one 6 × 9 cm bag. Never round measured quantities to pieces. Warn about duplicate references and count mismatches for fitted electronic components; packing labels are descriptive references.

Remove marks a line “Will remove” with immediate draft Undo. Review N changes previews all additions, edits and removals; Confirm writes, then a visible receipt offers server Undo. Discard leaves ERP unchanged. Preserve drafts across part creation and in-app navigation; warn before losing edits. No write on field blur.

Search covers IPN, name, description, MPN, reference and notes. Chips: All, Short, Unpriced, Sub-assemblies, Consumables, Optional, Changed. Show “7 of 42 lines”; hidden edits remain in Review. Search must cover the whole loaded BOM or fetch all pages, never only the visible rows.

Sub-assembly chevrons expand lazily, with Collapse all and breadcrumb context. Display quantity per immediate parent and effective quantity for the selected top-level batch. Keep indentation bounded on phones. Descendants are read-only here; Edit child BOM opens that assembly and names other affected parents. Detect cycles and shared demand; do not total both an assembly and its expanded children.

Phone — 375 px first

< Assemblies       Robot Cow A
BOM: Needs check   [Edit] [...]
[Search this BOM____________]
[All] [Short 2] [More filters]
Build qty [10]     [+ Add line]
------------------------------
R1,R2  EE-C-0142 >  Resistor
Qty [2] each     [Line details]
Free 12 | Need 20 | Short 8 >
Cost $0.08/board     [Remove]
> Controller board   1 each
SN-LABEL  Tape       27 mm
Consumable | Packing low >
------------------------------
Known $12.40 | 2 unpriced
[Discard]   [Review 3 changes]

Cards retain stock/shortage visibility. Tapping the part opens its page; chevron, edit and remove are separate controls. References/notes wrap. Use 16 px inputs, generous touch targets and accessible text with icons. Sticky controls respect keyboard and safe areas; the last line stays reachable. Existing body-mounted dialogs and visualViewport behavior apply.

Desktop — same actions, compact table

Robot Cow A / BOM [Edit] [+ Add] [More]
[Search________] [Short] [Build qty 10]
Part / ref       Qty   Free/need   Cost   Action
v Controller      1      5/10     $8.00   ...
  > U1 MCU        1     12/10     $3.20   Open
R1,R2 Resistor   [2]    12/20     $0.08   Remove
SN-LABEL Tape    [27mm] Packing   $0.04   ...
Known $12.40 | 2 unpriced | Review 3 changes

Use Tabler tables/cards, existing icons and theme tokens; sticky column headers under the app bar, sticky totals/action strip below. Keyboard Tab/Enter navigation must work. Advanced fields expand on demand. Mock values illustrate layout only; no new grid framework is needed for Phase 1.

Stock and money that can be trusted

Each line shows free stock, required quantity for the selected batch, shortage and line-limited can-build where meaningful. Link stock to the part's Stock tab, missing price to Cost, and child assemblies to BOM. Show on-order separately. Use native requirements/availability; subtract reservations once and exclude unusable stock. Unknown is distinct from zero.

Keep ERP Can build consistent with SOP-028: optional/consumable lines do not constrain it. The packing memory requires tape, labels and bags to be visible; add a separately labelled packing check without changing those flags. A consumable count may be stale because builds do not decrement it. Shared substitutes cannot fund two requirements simultaneously; unsupported combinations show an explanation and native planning link.

Reuse cost.py, keyed by BOM-line/part IDs, with explicit batch quantity and source timestamp. Show per-unit, per-board and batch consumed-material cost; supplier MOQ/pack cash outlay is separate. Include consumables; optional/DNP lines get a separate subtotal unless selected. Roll up each child once, identifying stock-cost versus rolled-material basis. No labor/overhead implied.

Label mixed stock/supplier results as estimates. Apply SOP-027 evidence/freshness rules before claiming completeness; current code needs review for estimated stock, stale quotes and quantity breaks. Show Known subtotal + N unpriced, withholding the full total. Never use sale_price_min; kits carry their own selling price. Invalidate object/cost/report caches after confirm and undo.

KiCad, copying and export

bom_import.py already parses decimal CSV, delimiter/header aliases, DNP, missing identifiers and reference-count problems (500-row limit). partforms.import_csv() matches IPN then MPN, updates quantity/reference/optional, and preserves notes, consumables, substitutes and omitted lines. MPN fallback currently takes the first match; ambiguous matches must require resolution.

Compare with KiCad / Update from KiCad stays on the BOM tab: choose a CSV or a linked, pinned repository export, then see Added, Changed, Unchanged, Not in KiCad and Unmatched. Compare is read-only; Update selects changes into the normal draft/review flow. Preserve pre-existing unsaved edits or require explicit discard before import. Store filename/hash and repo commit when available.

Never silently delete “Not in KiCad”: this includes bare PCBs, bags, labels and coating. Proposed removals are explicit unchecked choices. Show before/after fields, DNP changes and unresolved identities; require resolution or an acknowledged exclusion list before applying. Mixed fitted/DNP rows for one part hit today's one-line-per-part constraint: stop and resolve against installed native capabilities, never silently merge.

Copy BOM from assembly searches a source and previews merge versus replace, including native flags/substitutes and inherited-line ownership. Default merge; replacement lists every removal. Reuse native duplicate-with-BOM for a new assembly/revision; use the existing diff path for an existing destination, preserving its identity and stock.

Export CSV / Google Sheet offers top-level or expanded snapshot, with assembly/revision, date, units, flags, references, source and completeness. Default excludes costs for unauthorized roles. Prefer native export and the shared Reports/Google adapter; label Sheets as snapshots with an app backlink. No spreadsheet-to-ERP sync. Protect spreadsheet text from formula interpretation.

BOM checked and controlled revisions

Add Check BOM: inspect required fields, qualified components/substitutes, units, reference conflicts and packing omissions, then preview/confirm native validation. Show who/when where the API provides it. Saving or importing never auto-validates; keep material availability, price completeness and engineering approval as separate statuses.

Assembly revision already means a new ERP part/IPN (partforms.plan_revision/apply_revision uses native duplication with copy_bom). Keep that separate from controlled-file revision letters, which advance on release. Substitutes follow SOP-008's ERP-only change rule; do not force a hardware revision for every edit.

Extend the existing controlled-file workflow with the assembly PK/revision, native BOM checksum and a normalized BOM snapshot/hash at release. Include fields native validation may omit, such as substitutes/notes, and child revision dependencies. Later BOM edits show BOM changed since WI Rev A — review required, linking Documents and the proposed Reports flag. Reconcile external ERP edits too.

Never rewrite a released WI or historical build snapshot. Keep the released PDF/file bytes and exact revision links; start a new document draft through the established workflow. Engineering records whether an edit needs a new assembly revision, document revision or a documented no-impact review. Verify existing build pinning before relying on it: objects.py can derive displayed BOM revision from current part data.

Write boundary and risks to fix before shipping

All mutations remain server-authorized for Engineering/Admin using the Engineering department token (require_eng), trusted-browser checks and an audit receipt. Production/Purchasing retain their permitted read access; costs stay Engineering/Admin. No browser ERP token and no permission widening to bypass a 403.

Reuse /bom/api/assembly/{pk}, /parts, /import, /preview, /confirm, /undo. Native writes are POST/PATCH/DELETE /api/bom/… and /api/bom/substitute/…; actions.ERPClient is transport. Present capability-aware controls rather than assuming that the truncated read model can be posted back safely.

Current confirm rejects changes since preview, but Undo does not check intervening edits. Calls are sequential, not an ERP transaction; mid-batch failures can leave partial changes. Tokens live in memory, are lost on restart and have one-hour cleanup semantics. Before Phase 1: retain operation receipts durably, recheck permission/lock/open builds at execution, guard confirm/undo against stale state, reconcile uncertain responses and read back results. Never blindly retry a partially applied batch.

Deletion currently blocks when open builds exist. Retain that rule and review quantity/substitute changes against allocated work. Restoration must preserve all native fields; inherited lines must not mutate a template unnoticed. Use stable line IDs, explicit incomplete-read errors, pagination and cache invalidation. Bound tree loading and avoid one stock/cost request per rendered row.

Phases and acceptance — focused days, not elapsed promises

  1. Inline essentials, 3–4 days. Verify installed schema; harden confirm/undo; add in-tab add/remove/qty + search, draft review and return navigation. Preserve current advanced editor access until replacement is complete. Pass: add tape at 27 mm, change qty, remove, confirm and undo entirely from the tab; another user's edit is never overwritten.
  2. Line detail and visibility, 2–3 days. References/notes, flags/substitutes, create-part return, tree, line costs/shortages and sticky totals; Assemblies/Reports links. Pass: shared components, decimal consumables, unpriced lines and optional parts give clearly labelled results; incomplete reads cannot masquerade as empty BOMs.
  3. Reuse and reconciliation, 2–3 days. KiCad comparison/update, source copy, CSV/Sheet snapshots and native Check BOM. Pass: DNP/unmatched/ambiguous cases visible, packaging preserved, every removal reviewed; exported identity/units match the ERP readback.
  4. Release traceability, 1–2 days. Add BOM release fingerprints, out-of-date flags and exact build references using document-release-workflow and app-reporting-plan. Pass: edits after released WI trigger review; older builds keep their original evidence. Any hard build interlock is a separately agreed behavior.

Total: 8–12 days, assuming existing Google export and release adapters are reusable; allow 1–2 extra days if native-version or durable-recovery gaps are larger. Each phase includes relevant tests and review. Phase 1 does not wait for a general reporting system or ERP migration.

tests/ui/fixtures.py:44 currently has one simple resistor BOM; sheets_webkit.py visits #part/7/bom but has no /bom/api editor fixtures. Extend with empty/large BOMs, long references, decimals, nested/inherited lines, substitutes, role denial, lock/open-build conflicts, import diffs and recovery/undo states. Reuse tests/test_partforms.py and cost/object tests for backend behavior.

Before a future release: mocked backend tests plus app-ui-check on iPhone SE/13, Android and desktop, light/dark, keyboard open, every dialog/menu and last-row scrolling. Include edit/part-link separation, draft navigation and totals visibility. Rehearse against sandbox ERP; release only through app-release. No tests, services or deployments were run for this planning task.

Remaining checks and source context

Engineering must establish the installed native schema/validation endpoint, copy fidelity, effective inherited BOM reads and overage behavior. Decide packing count freshness and the released-WI build interlock with Production. Verify MPN search behavior, export adapter availability and whether existing releases/builds retain sufficient BOM identity; these are implementation checks, not assumed capabilities.

Rules read: embeddedera-app, company-operating-system-strategy, document-release-workflow, app-reporting-plan, packing/pricing memories and SOP-002/006/008/027/028. SOP-003 is Stock Locations and Movement, not the Part/BOM SOP; it was checked too. Future implementation should update the relevant existing SOPs for the new entry points, without duplicating their procedures.

Only this proposal was written; no code, ERP data, other notes, memory, commits or sync. No helper models ran: capacity telemetry was missing and read-only helper confinement unavailable under SOP-025. Findings and recommendations were reviewed in the primary Codex session.

10-line summary

Edit the BOM on its assembly page.
Ship inline add, remove, quantity and search first.
Keep preview, confirm and conflict-safe undo.
Reuse native InvenTree fields and validation.
Make measured consumables and packing visible.
Show honest stock, shortage and cost indicators.
Expand sub-assemblies without losing context.
Preview KiCad updates and preserve shop-added lines.
Flag changes against released instructions and builds.
Gate every phase on phone usability and sandbox checks.

Addendum 2026-10-05 — Sheet round trip with check-out / check-in (owner decision)

Owner: "What if we download this BOM, modify it, then upload?" … "Same for parts. We need to make sure we kick everyone out before downloading and uploading. We can use our Google Drive for it." New order: build the Google Sheets round trip first (~2–3 days for BOMs, +~2 days for parts), then Phase 1 inline essentials for small fixes. Both share the hardened write path (preview diff, no half-applied changes, reliable Undo).

Check-out (download) — on an assembly's BOM tab ("Edit in Google Sheets") or on the Parts list for a filtered selection ("Edit these parts in Sheets"): 1. The app locks those records: BOM lines of that assembly, or the selected parts. Everyone else sees "Checked out by since