Skip to content

feat: add piece_count and piece_size fields to BomItem for cut-to-length parts - #12422

Merged
SchrodingersGat merged 10 commits into
inventree:masterfrom
amanjain57-gif:feature/bom-cut-to-length-parts
Aug 15, 2026
Merged

feat: add piece_count and piece_size fields to BomItem for cut-to-length parts#12422
SchrodingersGat merged 10 commits into
inventree:masterfrom
amanjain57-gif:feature/bom-cut-to-length-parts

Conversation

@amanjain57-gif

Copy link
Copy Markdown
Contributor

Summary

Addresses #10274

Manufacturing BOMs frequently require multiple pieces of a specific size cut from continuous stock (cables, tubing,
structural profiles). Currently the only way to express "10 pieces of 250mm cable" is to enter the total length (2.5m)
as quantity, which loses the piece-count information that purchasing and production need.

Changes

Adds two optional fields to BomItem:

  • piece_count: number of discrete pieces required (default: 1)
  • piece_size: size/length of each piece (e.g. "250 mm")

When piece_size is specified, the total quantity is auto-calculated as piece_count × piece_size, maintaining full
backward compatibility (existing items effectively have piece_count=1 and empty piece_size).

Backend

  • New model fields with migration
  • Updated recalculate_quantity() to compute total from piece_count × piece_size when piece_size is set
  • Added fields to BOM item hash for validation checksum

API

  • Serializer exposes piece_count and piece_size fields

Frontend

  • BOM creation/edit form includes the new fields
  • BOM table shows piece_count and piece_size as optional (hidden by default) columns

Example

A BOM line for "10 pieces of 250mm aluminum profile" (part units: m):

  • piece_count: 10
  • piece_size: "250 mm"
  • Auto-calculated quantity: 2.5 (meters)

This preserves the per-piece information for production while correctly computing total material requirement for
purchasing.

…gth parts

Manufacturing BOMs frequently require multiple pieces of a specific size
cut from continuous stock (cables, tubing, structural profiles). Currently
the only way to express "10 pieces of 250mm cable" is to enter the total
length (2.5m) as quantity, which loses the piece-count information that
purchasing and production need.

This adds two optional fields to BomItem:
- piece_count: number of discrete pieces required (default: 1)
- piece_size: size/length of each piece (e.g. "250 mm")

When piece_size is specified, the total quantity is auto-calculated as
piece_count × piece_size, maintaining full backward compatibility (existing
items effectively have piece_count=1 and empty piece_size).

Changes:
- Backend: new model fields, migration, updated recalculate_quantity()
  logic, hash_fields for BOM validation
- API: serializer exposes piece_count and piece_size
- Frontend: BOM form includes the new fields, BOM table shows them as
  optional columns

Addresses inventree#10274
@netlify

netlify Bot commented Jul 19, 2026

Copy link
Copy Markdown

Deploy Preview for inventree-web-pui-preview canceled.

Name Link
🔨 Latest commit 8d92cc4
🔍 Latest deploy log https://app.netlify.com/projects/inventree-web-pui-preview/deploys/6a807c47ef2a5b00082ca9c6

@SchrodingersGat

Copy link
Copy Markdown
Member

@amanjain57-gif an interesting idea here, thanks for submitting.

I think that you can achieve this with a single additional field, not two.

If you remove the "piece_size" field and just use quantity, then the additional "piece_count" field can be used to reflect multiple pieces.

e.g. a BOM with multiple lengths of wire

Field Value Description
quantity 200mm Length of individual cut wires
piece_count 10 10x separate multiples of 200mm

Thus the total requirement is 2m of wire, but we can see it is in 10x pieces of 200mm

@SchrodingersGat SchrodingersGat left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reduce to a single additional field as discussed

Remove the piece_size field entirely. The existing quantity field already
represents the per-piece size/length, so piece_count multiplied by
quantity gives the total material requirement.

Example: quantity=200mm, piece_count=10 → total 2m of wire in 10 pieces.

Changes:
- Remove piece_size model field, serializer field, and frontend column/form
- Update migration to only add piece_count
- Update get_required_quantity() to multiply by piece_count
- Restore original recalculate_quantity() without piece_size logic
@amanjain57-gif

Copy link
Copy Markdown
Contributor Author

Thanks for the feedback! Simplified to a single piece_count field as suggested. quantity now represents per-piece size, and total material = quantity × piece_count. Removed piece_size from model, migration, serializer, and frontend.

@SchrodingersGat

Copy link
Copy Markdown
Member

@amanjain57-gif thanks for the updates.

Can you please also add some unit tests here, for (at least) the following:

  • Expected "quantity required" calculations based on the new field
  • API GET / POST tests for the new field

@SchrodingersGat

Copy link
Copy Markdown
Member

You will also need to add comprehensive documentation for the new extension

@amanjain57-gif

Copy link
Copy Markdown
Contributor Author

@SchrodingersGat Working on both requests:

  1. Unit tests — Adding tests for get_required_quantity() calculations with piece_count, API GET/POST/PATCH tests for the new field, and validation tests (default=1, positive-only).
  2. Documentation — Adding a section to the BOM docs explaining piece_count with examples (e.g., quantity=200mm, piece_count=10, total=2m of wire).

Will push shortly.

@amanjain57-gif

Copy link
Copy Markdown
Contributor Author

Done — pushed unit tests and documentation:

Tests added (11 total):

  • 6 model-level tests: default value, quantity multiplier calculation, interactions with attrition/setup_quantity/rounding, and validation (rejects 0 and negatives)
  • 5 API tests: GET returns piece_count, POST with/without piece_count, PATCH updates, invalid values return 400

Documentation:

  • Added piece_count to the BOM Line Items table in docs/docs/manufacturing/bom.md
  • Added a "Piece Count (Cut-to-Length Parts)" section with the formula, two worked examples (wire harness, hydraulic tubing with attrition), and usage tips
  • Added to BOM Checksum fields list

@amanjain57-gif

Copy link
Copy Markdown
Contributor Author

Fixed ruff check failure — replaced Unicode multiplication sign (×) with plain x in docstrings (RUF002).

@SchrodingersGat

Copy link
Copy Markdown
Member

@amanjain57-gif looking good! Please fix:

  1. Add an entry to api_version.py
  2. Add an entry to CHANGELOG.md
  3. Fix style issues

- Bump INVENTREE_API_VERSION to 531 with entry for piece_count field
- Add CHANGELOG.md entry under Unreleased > Added
- Fix RUF001: replace ambiguous × with x in serializers.py help_text
@amanjain57-gif

Copy link
Copy Markdown
Contributor Author

@SchrodingersGat Thanks — all three addressed:

  1. api_version.py — bumped to v531 with an entry for the new piece_count field.
  2. CHANGELOG.md — added an entry under Unreleased → Added.
  3. Style — fixed the remaining RUF001 (ambiguous ×x) in the piece_count serializer help text. ruff check + ruff format --preview (v0.15.12, matching .pre-commit-config.yaml) are clean locally.

The API Schema check should also resolve now, since the version bump lets the paths filter pick up the API change.

@SchrodingersGat SchrodingersGat added this to the 1.6.0 milestone Aug 11, 2026
@SchrodingersGat SchrodingersGat added enhancement This is an suggested enhancement or new feature api Relates to the API User Interface Related to the frontend / User Interface labels Aug 11, 2026
@SchrodingersGat

Copy link
Copy Markdown
Member

@amanjain57-gif nice, this is looking pretty clean now

@SchrodingersGat

Copy link
Copy Markdown
Member

Still need to address outstanding CI failures

The 0153 AddField recorded help_text with a Unicode multiplication sign
(×), while the model field uses plain 'x' after the RUF001 fix. This
mismatch made makemigrations --check flag an unstaged
0154_alter_bomitem_piece_count migration, failing the DB test CI jobs.

Update the original migration's help_text (and docstring) to plain 'x'
so the field definition matches the model, keeping a single clean
migration instead of add-then-alter.
@amanjain57-gif

Copy link
Copy Markdown
Contributor Author

@SchrodingersGat Fixed the outstanding CI failure. The DB test jobs were failing on the unstaged-migration check:

There are 1 unstaged migration files:
 - src/backend/InvenTree/part/migrations/0154_alter_bomitem_piece_count.py

Root cause: migration 0153's AddField still recorded the help_text with a Unicode ×, while the model field was switched to plain x in the RUF001 fix. That one-character mismatch made makemigrations --check want a redundant alter_bomitem_piece_count migration.

Since piece_count is new in this PR, I updated the original 0153 migration's help_text (and docstring) to plain x so it matches the model — keeping a single clean migration rather than add-then-alter. Field definitions now match, so the check should pass. (The earlier lone Frontend Firefox failure looked flaky/unrelated to this backend change.)

@codecov

codecov Bot commented Aug 12, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 86.81%. Comparing base (e4b23b4) to head (8d92cc4).

Additional details and impacted files
@@            Coverage Diff             @@
##           master   #12422      +/-   ##
==========================================
- Coverage   86.83%   86.81%   -0.03%     
==========================================
  Files        1449     1450       +1     
  Lines       96884    96982      +98     
  Branches    11185    11271      +86     
==========================================
+ Hits        84132    84195      +63     
- Misses      12688    12723      +35     
  Partials       64       64              
Flag Coverage Δ
backend 90.84% <100.00%> (+<0.01%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

Components Coverage Δ
Backend Apps 92.22% <100.00%> (+<0.01%) ⬆️
Backend General 93.75% <ø> (-0.04%) ⬇️
Frontend 79.66% <ø> (-0.07%) ⬇️
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

BomItem.quantity is a derived field, recalculated from raw_amount on
every save() via recalculate_quantity(). Setting item.quantity directly
was overwritten back to the fixture value on save, so the tests computed
against quantity=3 and failed. Use set_quantity() (which sets raw_amount)
to match how quantity is meant to be updated.
@amanjain57-gif

Copy link
Copy Markdown
Contributor Author

Fixed the 5 failing test_bom_item tests. Root cause: BomItem.quantity is a derived field — it's recalculated from raw_amount on every save() via recalculate_quantity(). The tests set item.quantity = N directly, which got overwritten back to the fixture value on save, so get_required_quantity() was computing against the wrong quantity.

Switched them to item.set_quantity(N) (which sets raw_amount), matching how quantity is meant to be updated elsewhere. The piece_count multiplier logic itself was correct.

@SchrodingersGat

Copy link
Copy Markdown
Member

@amanjain57-gif you will need to address the conflict here due to API version updates

…o-length-parts

# Conflicts:
#	src/backend/InvenTree/InvenTree/api_version.py
@amanjain57-gif

Copy link
Copy Markdown
Contributor Author

@SchrodingersGat Conflict resolved — merged latest master. Upstream had taken v531 (PR #12635), so I moved the piece_count entry to v532 and bumped INVENTREE_API_VERSION accordingly. Branch is mergeable again.

@amanjain57-gif

Copy link
Copy Markdown
Contributor Author

Heads up on CI: the only red check is Tests [Firefox 1 / 2], and the three failures are the known-flaky Firefox E2E specs — pui_dashboard.spec.ts › Dashboard - Basic and pui_build.spec.ts › Build Order - {Build Outputs, Consume Stock} — all failing with locator.waitFor/click: Test ended plus Firefox juggler/favicon browser errors. None touch BomItem/piece_count, and Firefox 2 / 2 passed. Looks related to the flaky-Firefox work in #12640. A re-run should clear it (I don't have permissions to trigger one). Happy to rebase if that helps.

@matmair

matmair commented Aug 15, 2026

Copy link
Copy Markdown
Member

That pr is already in your branch; I am not sure how a rerun would help

@amanjain57-gif

Copy link
Copy Markdown
Contributor Author

You're right — #12640 is already in the branch from the master merge, so a re-run wouldn't pull in anything new. My mistake referencing it; it also only touched pui_transfer.spec.ts, which isn't one of the failing specs.

What I actually meant is that the three failures (pui_dashboard.spec.ts › Dashboard - Basic, pui_build.spec.ts › Build Order - Build Outputs / Consume Stock) look like transient Firefox E2E failures — they die with locator.waitFor/click: Test ended alongside Firefox juggler/favicon browser errors rather than assertion failures, and none of them exercise the piece_count change (a BomItem model/serializer field plus a BomTable column). Firefox 2 / 2 passed.

I've pushed a fresh commit to trigger a clean run — let's see if they come back green. If you're seeing these as genuinely caused by this PR rather than environmental, I'd appreciate a pointer and I'll dig in; I can't reproduce Firefox E2E reliably locally.

@SchrodingersGat

Copy link
Copy Markdown
Member

@amanjain57-gif please note that in future I have no interest in a discussion with your AI agent.

@SchrodingersGat
SchrodingersGat merged commit ee4ad7f into inventree:master Aug 15, 2026
46 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

api Relates to the API enhancement This is an suggested enhancement or new feature User Interface Related to the frontend / User Interface

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants