Production Reference Public

Work Centers & BOM (Mfg)

Advanced Manufacturing Work Centers & BOM (Mfg) Define the machines and stations where production happens, and the multi-level recipes (Bills of Materials) that say exactly what…

Guide version: r1 Module version: 1.0.0 Updated: 2026-07-22 Estimated time: 19 min 2 views
Advanced Manufacturing

Work Centers & BOM (Mfg)

Define the machines and stations where production happens, and the multi-level recipes (Bills of Materials) that say exactly what each product is made of and how it is built — the engineering master data that feeds every Work Order downstream.

ℹ️
This is the ADVANCED area — not the base one. These two screens live under production/WorkCenters and production/Bom, are gated by the manufacturing_* permissions, and store their data in dedicated manufacturing_* tables. They are separate from the lightweight Base Production screens (production/Work_centers and production/Boms, described in Work Centers and Bill of Materials). In the sidebar they read "BOM (Mfg)" vs. "Bill of Materials" — don't confuse the two entries.

How the Mfg versions differ from the base versions

The advanced Work Center and BOM screens add the structure a real shop floor needs. Compared to the base equivalents, they give you:

????
Separate manufacturing_* tables

Work centers store to manufacturing_work_centers; BOM headers, items and routing store to manufacturing_bom, manufacturing_bom_items and manufacturing_bom_operations. These are distinct from the base Production tables, so the two areas never share records.

????
BOM versioning & status

Every BOM header carries a free-text Version, a status (Draft → Pending Approval → Approved → Obsolete), an effective-date window, and Active / Default flags — so the right revision is chosen when orders are raised.

????
Items & operations edited in modals

A BOM's component lines (Items) and routing steps (Operations) are added and removed through inline modals launched from the list — you never leave the BOM list to build the recipe.

????
Multi-level / sub-assemblies

A BOM Item can be typed as a Sub Assembly — a part that is itself manufactured. The manufacturing_bom_items table stores a parent_bom_item_id link, so recipes can nest into a true multi-level BOM.

⚠️
Product and items are free text here. There is no product/item picker on these forms — you type the Product name and each Item Name exactly. The underlying product_id / item_id default to 0 and are not set from the UI, so a Mfg BOM is not truly joined to the Inventory items master. Typos create disconnected recipes. (The base Bill of Materials screen behaves differently — check which one you are on.)

Work Center — fields

A Work Center is any production resource where work is performed: a machine, a manual labor station, an assembly cell, an inspection point, or a packaging station. Each one carries a capacity per hour, an hourly cost and a default setup time. Open Manufacturing → Work Centers and click Add Work Center to create one.

FieldMeaningRequiredNotes
code — Code Short unique identifier for the work center (e.g. WC-001). Required Free text. Placeholder "e.g. WC-001". The database enforces uniqueness of code among non-deleted rows — a duplicate save fails with a generic error, not a friendly "code exists" message.
name — Name Human-readable work center name. Required Free text. The list is sorted alphabetically by Name.
work_center_type — Type Category of the resource. Optional Select2 dropdown: Machine, Labor, Assembly, Inspection, Packaging. Defaults to Machine on new records (so the form is never blank). Validated as required on save; rendered as a coloured label in the list.
description — Description Free-text notes about the work center. Optional Textarea, 3 rows.
capacity_per_hour — Capacity/Hr How many units this work center can process per hour. Optional Number, step 0.01, defaults to 0. Stored as NULL if left empty. Shown in the list with its capacity UOM symbol, or - if zero/empty.
capacity_uom_id — Capacity UOM Unit of measure for the capacity figure. Optional Dropdown of active manufacturing UOMs (name + symbol) with a blank - option. Stored NULL if blank.
cost_per_hour — Cost/Hr Hourly operating cost of this work center (used for costing operations). Optional Number, step 0.01, defaults to 0. Shown formatted to 2 decimals.
setup_time_minutes — Setup Time (min) Default minutes to set up this work center before a run. Optional Integer, min 0, step 1, defaults to 0. Stored on the work center — but each operation captures its own setup time separately and does not auto-copy from here.
location — Location Physical location / area of the work center. Optional Free text. Shown as - if empty.
is_active — Active Whether the work center is available for use. Optional Checkbox, checked by default on new records. Only active work centers appear in the BOM Operations work-center dropdown. Inactive rows show a grey "Inactive" label.

Work Center Type & status legend

MachineType = machine — automated equipment.
LaborType = labor — a manual work station.
AssemblyType = assembly — an assembly cell.
InspectionType = inspection — a QC / check point.
PackagingType = packaging — a packing station.
ActiveAvailable for BOM routing.
InactiveHidden from new operation dropdowns.

The Work Centers list

The work-centers-table DataTable shows one row per work center with these columns:

ColumnShowsNotes
CodeThe unique code.
NameThe work center name.List is sorted alphabetically by this column.
TypeMachine / Labor / Assembly / Inspection / Packaging.Rendered as a coloured label.
Capacity / HrCapacity figure + UOM symbol.Shows - if zero or empty.
Cost / HrHourly cost, 2 decimals.
LocationPhysical area.Shows - if empty.
StatusActive (green) or Inactive (grey).
ActionsPer-row cog (gear) menu: Edit, Delete.Not exported.
????
The list can be exported to Excel (columns 0–6 via the appTable export). A work_center_type filter is supported by the controller, but the list view does not render a filter dropdown for it, so it is effectively unused in the UI.

BOM anatomy — Header, Items, Operations

A Bill of Materials (BOM) is the recipe for a product. It has three parts, each edited on its own screen and each with its own field table below:

BOM Header — fields

The header is the recipe's top-level definition: what product it makes, how many units it yields, its version, status and validity window. Open Manufacturing → BOM and click Add BOM (the production/Bom/modal_form screen).

FieldMeaningRequiredNotes
bom_code — BOM Code Unique code identifying this BOM. Required On a new BOM the field is pre-filled with the next suggested code (prefix BOM + 6-digit zero-padded sequence, e.g. BOM-000001). The DB enforces uniqueness among non-deleted rows.
product_name — Product Name of the finished product this BOM produces. Required Free text — there is no product picker; type the name exactly. A hidden product_id (defaults 0) exists but is not exposed on the form.
bom_type — Type Nature of the BOM. Optional Dropdown: Manufacturing, Assembly, Kit, Engineering. Defaults to Manufacturing. Rendered as a coloured label in the list.
version — Version Revision label of the BOM. Optional Free text, defaults to 1.0. Used to distinguish recipe revisions of the same product.
quantity — Quantity How many units of the product this BOM yields (the base/batch quantity that item quantities are relative to). Required Numeric, step 0.0001, defaults to 1. Shown to 4 decimals on the view page.
uom_id — UOM (next to Quantity) Unit of measure for the produced quantity. Required Dropdown of active UOMs. Uses validate-hidden so the required rule still fires even though Select2 hides the native control.
status — Status Lifecycle stage of the BOM. Optional Dropdown: Draft, Pending Approval, Approved, Obsolete. Defaults to Draft. Freely selectable — there is no enforced workflow guard.
effective_from — Effective From Date this BOM version becomes valid. Optional HTML date input. Stored NULL if blank; shows N/A on the view page when empty.
effective_to — Effective To Date this BOM version stops being valid. Optional HTML date input. Stored NULL if blank; shows N/A on the view page when empty.
notes — Notes Free-text remarks about the BOM. Optional Textarea, 3 rows. Shown on the view page (HTML-escaped, line breaks preserved).
is_active — Active Whether this BOM is currently usable. Optional Checkbox, checked by default on new BOMs. Independent of the status field.
is_default — Default BOM Marks this BOM as the primary recipe for its product. Optional Checkbox, unchecked by default. No uniqueness is enforced — nothing stops you flagging several BOMs for the same product as Default.
⚠️
The header form only sets the status enum. The separate approval_status, approved_by and approved_at columns are never populated by these screens — there is no distinct "approve" action, just the Status dropdown.

BOM Item — fields

Each BOM Item is one material line — a raw material, component, sub-assembly or consumable that the product consumes. Add items via the BOM Items modal (production/Bom/items_modal/{bom_id}), reached from the cog menu on the BOM row. There is an inline add-row form; the form resets after each successful add.

FieldMeaningRequiredNotes
item_name — Item Name Name of the material/component consumed. Required Free text — no item picker. Placeholder "Item Name *". A hidden item_id (defaults 0) exists but is not exposed.
item_type — Item Type Classification of the component. Required Dropdown: Raw Material, Component, Sub Assembly, Consumable. No blank default is preselected. Use Sub Assembly for parts that are themselves manufactured — this is what makes the BOM multi-level. Rendered as a coloured label.
quantity — Qty How much of this material is needed (per the BOM's produced quantity). Required Numeric, step 0.0001. Shown to 4 decimals with UOM symbol.
uom_id — UOM Unit of measure for the item quantity. Required Dropdown of active UOMs. The add-form control is not marked required in the HTML, but the controller validates uom_id as required|numeric on save.
scrap_percentage — Scrap% Expected waste percentage for this material. Optional Numeric, step 0.01, defaults 0. Shown as e.g. 2.00%.
is_optional — Optional Whether the item is optional rather than mandatory. Optional Not present in the inline add form — always saved as 0 (Required) when added here. The list/view still displays Optional vs. Required.
notes — Notes Free-text remarks for the item. Optional Not present in the inline add form; stored blank when added here. Displayed in the items table (- if empty).
ℹ️
The bom-items-table columns are: Item Name, Type, Quantity, Scrap %, Optional, Notes, and a red X to delete the line. Because the add form omits is_optional and notes, every item added here shows as Required with an empty Notes cell.

BOM Operation — fields

Each BOM Operation is one routing step (e.g. Cutting, Welding), numbered in sequence and performed at a Work Center. Add operations via the Operations modal (production/Bom/operations_modal/{bom_id}), reached from the cog menu on the BOM row. There is an inline add-row form; the form resets after each successful add.

FieldMeaningRequiredNotes
operation_number — # Sequence number of the routing step; operations sort ascending by this. Optional Integer, defaults to 10 (convention: 10, 20, 30… to leave gaps for insertion). Falls back to 10 server-side if left blank.
operation_name — Operation Name of the routing step (e.g. Cutting, Welding). Required Free text. Placeholder "Operation *".
work_center_id — Work Center The work center where this operation is performed. Required Dropdown showing code - name of active work centers only. Validated required|numeric. If no active work centers exist you cannot add an operation.
setup_time_minutes — Setup Minutes to set up before running this operation. Optional Integer, defaults 0. Shown as "N min". Captured per-operation — does not auto-copy from the work center's own setup time.
run_time_per_unit_minutes — Run/Unit Minutes to process one unit at this operation. Required Numeric, step 0.01. Shown to 2 decimals + " min".
labor_cost_per_hour — Labor/Hr Hourly labor cost for this operation. Optional Numeric, step 0.01, defaults 0. Shown to 2 decimals.
machine_cost_per_hour — Mach/Hr Hourly machine cost for this operation. Optional Numeric, step 0.01, defaults 0. Shown to 2 decimals.
overhead_percentage — Overhead % Overhead percentage applied to this operation's cost. Optional Stored in the DB (defaults 0) and accepted by the server, but has no input in the add form and is not shown in the operations table.
description — Description Free-text description of the operation. Optional Accepted by the server but has no input in the add form.
is_outsourced — Outsourced Whether the operation is done by an external supplier. Optional Accepted (defaults 0) but has no input in the add form, so operations added here are always in-house (Outsourced = No). Displayed as Yes (warning) / No.
notes — Notes Free-text remarks for the operation. Optional Accepted by the server but has no input in the add form.
⚠️
The Operations add form omits several fields. description, overhead_percentage, is_outsourced and notes take server defaults, so every operation added here is in-house (Outsourced = No), 0 overhead, and has no description/notes — even though the bom-operations-table shows an Outsourced column (columns: #, Operation, Work Center, Setup, Run/Unit, Labor/Hr, Machine/Hr, Outsourced, delete X).

The BOM list & full-page view

Bill of Materials list

Open Manufacturing → BOM (production/Bom) for the master list. It carries a Status filter dropdown (Draft / Pending Approval / Approved / Obsolete / blank = all) and the bom-table DataTable:

ColumnShowsNotes
BOM CodeThe unique bom_code.
ProductThe free-text product name.
VersionRevision label.
TypeManufacturing / Assembly / Kit / Engineering.Coloured label.
QuantityProduced quantity.
StatusDraft / Pending / Approved / Obsolete.Coloured status label.
Created ByUser who created the BOM.
CreatedCreation date.
ActionsCog menu: View, BOM Items, Operations, (divider), Edit, Delete.Not exported; Excel export covers columns 0–7.

BOM full-page view

The cog menu's View opens a read-only page (production/Bom/view/{id}) headed "{BOM Code} - {Product Name}" with a Back to List button. It shows everything in one place — no editing happens here:

Header panel
BOM Code, Version, Type, Status badge, Quantity (4 decimals), Effective From, Effective To (each N/A if empty), Created, and Notes.
BOM Items table
Item Name, Type, Quantity, Scrap %, Optional, Notes. Reads "No items added yet" when empty.
Operations table
#, Operation, Work Center, Setup Time, Run Time/Unit, Labor Cost/Hr, Machine Cost/Hr, Outsourced. Reads "No operations defined" when empty.
Opening the view with a missing or invalid id returns a 404 (Not Found) page.

BOM status lifecycle

A BOM header moves through four statuses. The intended flow is left to right, but note the warning below — the code does not enforce it.

Draft
recipe being built
Pending Approval
submitted for review
Approved
released for production
Obsolete
retired / superseded
DraftInitial working state; the recipe is being built/edited. Grey label.
PendingSubmitted and awaiting approval. Orange label.
ApprovedReleased recipe, ready for production use. Green label.
ObsoleteRetired/superseded recipe. Red label.
⚠️
Status has no workflow enforcement. Any user with the manufacturing_bom permission can set a BOM directly from Draft to Approved to Obsolete — or backward — by editing it and picking a new value in the Status dropdown. There is no separate "approve" step and no guard that prevents reactivating an obsolete BOM. Treat the pipeline as an intended convention, not a locked process.

The Active and Default flags

Two checkbox flags on the header are independent of the status field:

Activeis_active — the BOM is usable. Toggled on edit, independent of status.
Defaultis_default — the primary recipe for its product. Uniqueness is NOT enforced.

BOM Type & Item Type legends

ManufacturingBOM type = manufacturing (default).
AssemblyBOM type = assembly.
KitBOM type = kit.
EngineeringBOM type = engineering.
Raw MaterialItem type = raw_material.
ComponentItem type = component.
Sub AssemblyItem type = sub_assembly — the multi-level building block.
ConsumableItem type = consumable.
OptionalBOM item is optional.
RequiredBOM item is required (the default when added via the UI).
Outsourced: YesOperation performed by an external supplier.
Outsourced: NoOperation performed in-house (the default here).

Actions & permissions

Both screens require module access to Manufacturing plus one screen-level permission — the granular *_create/_update/_delete keys exist in the permissions config but are not individually enforced here; the base key gates every action on the screen.

manufacturing manufacturing_work_center manufacturing_bom
ActionWhat it doesPermissionConfirmation
Add / Edit Work Center Opens the modal (empty for add, pre-filled for edit); Save inserts/updates a manufacturing_work_centers row (UUID, created_by, timestamps). New rows default is_active = 1. manufacturing_work_center None. Success shows the "record_saved" flash and injects/updates the row.
Delete Work Center Soft-deletes the work center (deleted = 1). manufacturing_work_center Standard delete-confirmation dialog.
Add / Edit BOM Inserts/updates a manufacturing_bom header (UUID, created_by, timestamps). Server defaults: version 1.0, type manufacturing, status draft, product_id 0 if none; new BOMs default is_active = 1. manufacturing_bom None. Success flash "record_saved".
View BOM Opens the read-only full-page view (header + all items + all operations). manufacturing_bom None.
Delete BOM Soft-deletes the header (deleted = 1). manufacturing_bom Standard delete-confirmation dialog.
Add / Delete BOM Item Inserts a manufacturing_bom_items row (is_optional forced 0, notes/item_id blank), or soft-deletes a line. manufacturing_bom Add: none (row injected, form resets). Delete: confirmation dialog.
Add / Delete Operation Inserts a manufacturing_bom_operations row (op-number defaults 10; outsourced/ overhead/description/notes take server defaults), or soft-deletes a line. manufacturing_bom Add: none (row injected, form resets). Delete: confirmation dialog.
Filter BOMs by Status Reloads the list filtered to the chosen status, or all when blank. manufacturing_bom None.
Close (modal) / Back to List Dismisses a modal (items/operations already added are already saved) or returns to the BOM list. n/a None.
BOM delete is a soft delete. The database has ON DELETE CASCADE foreign keys from items/operations to the BOM, but because the delete only sets deleted = 1, that cascade never fires — child item/operation rows are simply hidden with the parent, not physically removed.

Validation & result messages

Missing required fields raise the field's client-side "field_required" message. The server validates:

  • Work Center: code, name, work_center_type required; id numeric.
  • BOM header: bom_code, product_name required; quantity and uom_id required|numeric; id numeric.
  • BOM item: bom_id required|numeric, item_name required, item_type required, quantity and uom_id required|numeric.
  • BOM operation: bom_id required|numeric, operation_name required, work_center_id required|numeric, run_time_per_unit_minutes required|numeric.
⚠️
Result messages: save success shows "Record saved successfully" (record_saved); delete success shows "Record deleted successfully" (record_deleted). A failed save shows the generic error_occurred message; a failed delete shows "record could not be deleted" (record_cannot_be_deleted). Opening an Items/Operations modal with no bom_id returns {success:false, message: error_occurred}. Because duplicate codes are caught at the DB level, a duplicate code/bom_code fails with that generic error, not a friendly "code already exists" message.

SOP — Onboard a Work Center

????
Precondition: you have the manufacturing_work_center permission and the Manufacturing module is enabled.
  1. Open the list

    Go to Manufacturing → Work Centers and click Add Work Center.

  2. Identify it

    Assign a unique Code (e.g. WC-CNC-01) and a clear Name (e.g. "CNC Milling Machine 1").

  3. Pick the type

    Select the correct Type — Machine, Labor, Assembly, Inspection or Packaging.

  4. Enter capacity & cost

    Set Capacity/Hr with the matching Capacity UOM, and Cost/Hr (used for later costing). Add the default Setup Time (min) and Location if known.

  5. Keep it Active

    Leave Active checked so the center is selectable when you build BOM routing.

  6. Save

    Click Save and confirm the row appears with a green Active status.

SOP — Create a multi-level BOM

????
Precondition: the required Work Centers and active UOMs already exist, and you have the manufacturing_bom permission.
  1. Create the BOM header

    Manufacturing → BOM → Add BOM. Accept the pre-filled BOM Code (or set your own), type the Product name exactly, choose the Type, set the Version, Quantity and UOM. Keep Status = Draft while building, then Save.

  2. Add the components (Items)

    From the BOM row's cog menu, click BOM Items. In the inline row, type the Item Name, pick the Item Type, enter Qty + UOM, and optionally Scrap%. Click Add — the line appears and the form resets. Repeat for every component.

  3. Nest sub-assemblies

    For any part that is itself manufactured, set its Item Type = Sub Assembly. This is what makes the BOM multi-level — a sub-assembly should have its own BOM built the same way. (The parent_bom_item_id link underneath supports the nesting even though the list shows items flat.)

  4. Define the routing (Operations)

    From the cog menu, click Operations. In the inline row, set the operation number (10, 20, 30…), type the Operation name, pick the Work Center (only active ones appear), and enter Setup and Run/Unit times (plus Labor/Hr and Mach/Hr if you are costing). Click Add; steps sort by number. Repeat in sequence.

  5. Review the whole BOM

    Use the cog menu's View to check the header, every item (correct qty/UOM/scrap), and the full routing in one read-only page before you release it.

  6. Release it

    Edit the BOM and change Status to Pending Approval, then (after review) to Approved. Ensure Active is checked, and tick Default BOM if this is the primary recipe. Set Effective From/To to control the validity window.

⚠️
No automatic clone for revisions. To revise a BOM you create a new BOM (same product, a new Version label and a new BOM Code), re-add its items and operations, approve it and set it as Default — then edit the old BOM to Obsolete, uncheck Default (and optionally Active), and set its Effective To date.

Where this data goes next

Nothing is produced on these two screens — they are pure master data. Once your Work Centers and an Approved BOM exist, they become the source for the shop floor:

ℹ️
Other integrations. UOM dropdowns are populated from manufacturing_uom (active only — seeded units include Piece, Dozen, Kilogram, Gram, Liter, Milliliter, Meter, Centimeter, Hour, Minute). Work-center cost_per_hour and operation labor/machine costs feed production costing (manufacturing_standard_costs / manufacturing_actual_costs). And changes to a BOM are meant to be governed by Engineering Change Orders (manufacturing_eco, which reference bom_id) — managed on a separate screen, not editable here.
????
BOM code prefix gotcha. The suggested BOM Code always uses the hardcoded prefix BOM. The setting seeded as bom_code_prefix is not read by the code generator (which looks for a bom_prefix key), so editing that setting will not change the suggested prefix.
Was this guide helpful?

Report a content problem