Skip to content

[pull] master from inventree:master - #142

Merged
pull[bot] merged 1 commit into
Latitudes-Dev:masterfrom
inventree:master
Apr 22, 2026
Merged

pull[bot] merged 1 commit into
Latitudes-Dev:masterfrom
inventree:master

Conversation

@pull

@pull pull Bot commented Apr 22, 2026 •

Copy link
Copy Markdown

See Commits and Changes for more details.


Created by pull[bot] (v2.0.0-alpha.4)

Can you help keep this open source service alive? 💖 Please sponsor : )

Greptile Summary

This PR updates BOM checksum invalidation logic: BomItem.save() now collects assemblies from both the pre-save and post-save FK state (fixing missed updates when moving an item between assemblies), clear_bom() offloads a check_bom_valid task after bulk-deleting items, and hash_fields() adds 'part' and 'sub_part' alongside the existing 'part_id'/'sub_part_id' entries to fix delta detection for FK changes.

  • Adding FK object fields ('part', 'sub_part') to hash_fields() causes get_item_hash() to embed str(Part_instance) (i.e. full_name - description) in the checksum, so renaming any assembly or sub-part will silently invalidate all BOMs that reference it, even when no BOM structure has changed.
  • The hash algorithm change also means all previously validated BOMs will have stale checksums after deployment; check_bom_valid will flip every bom_validated flag to False with no migration path offered.

Confidence Score: 3/5

Not safe to merge — two P1 defects: part renames trigger false BOM invalidations, and the hash change mass-invalidates all existing validated BOMs without a migration.

The fix for detecting cross-assembly moves is correct, but the implementation of hash_fields() conflates delta detection keys with hash computation inputs. Using Part model objects in the hash makes the checksum sensitive to part names/descriptions, causing incorrect BOM invalidations on rename. Combined with the deployment-time breakage of all existing checksums, these are two present defects on the changed code path.

src/backend/InvenTree/part/models.py — specifically the hash_fields() method and its interaction with get_item_hash()

Important Files Changed

Filename Overview
src/backend/InvenTree/part/models.py Three targeted changes: (1) clear_bom now offloads check_bom_valid after deleting items; (2) BomItem.save() now collects assemblies from both old and new FK state; (3) hash_fields() adds 'part' and 'sub_part' FK objects alongside existing '_id' fields — introducing two P1 issues: spurious BOM invalidation on part renames, and silent mass-invalidation of all stored checksums on upgrade.
src/backend/InvenTree/part/test_bom_item.py New test_bom_validated covers creation, editing, FK reassignment, and deletion of BomItems; missing assertion on assembly_2's state after the cross-assembly move leaves partial coverage of the dual-update logic.

Sequence Diagram

sequenceDiagram
    participant User
    participant BomItem
    participant Part(Assembly)
    participant check_bom_valid task

    User->>BomItem: save() [part FK changed]
    BomItem->>BomItem: get_field_deltas() — detects 'part' in deltas
    BomItem->>Part(Assembly): db_instance.get_assemblies() [OLD assembly]
    BomItem->>Part(Assembly): self.get_assemblies() [NEW assembly]
    BomItem->>check_bom_valid task: offload_task(old_assembly.pk)
    BomItem->>check_bom_valid task: offload_task(new_assembly.pk)
    check_bom_valid task->>Part(Assembly): is_bom_valid() → get_bom_hash()
    Note over check_bom_valid task,Part(Assembly): hash now includes str(Part) = full_name+description
    check_bom_valid task->>Part(Assembly): bom_validated = False (if mismatch)

    User->>Part(Assembly): clear_bom()
    Part(Assembly)->>Part(Assembly): bom_items.all().delete()
    Part(Assembly)->>check_bom_valid task: offload_task(self.pk)
    check_bom_valid task->>Part(Assembly): bom_validated updated
Loading

Comments Outside Diff (3)

  1. src/backend/InvenTree/part/models.py, line 4089-4103 (link)

    Part rename triggers spurious BOM invalidation

    hash_fields() now includes 'part' and 'sub_part', which are FK fields. In get_item_hash(), getattr(self, 'part') returns the Part instance, and str(Part_instance) resolves to f'{self.full_name} - {self.description}' (see Part.__str__). This means renaming an assembly or sub-part will change the computed get_bom_hash() for every BOM that references it, causing is_bom_valid() to return False and check_bom_valid to subsequently flip bom_validated = False — even though the BOM structure itself is unchanged.

    The intent of adding 'part' and 'sub_part' is clearly to fix delta detection (so that any(f in deltas for f in self.hash_fields()) catches FK assignments like bom_item.part = assembly_2). But those same string names are also fed into the hash calculation and pick up the model's __str__ value. Only 'part_id' / 'sub_part_id' should be used in the hash itself.

  2. src/backend/InvenTree/part/models.py, line 4087-4103 (link)

    Hash algorithm change invalidates all existing validated BOMs

    Adding 'part' and 'sub_part' to hash_fields() changes the output of get_item_hash() for every existing BOM line, which in turn changes get_bom_hash() for every assembly. After deployment, is_bom_valid() will return False for all previously validated BOMs (stored checksum no longer matches the new calculation). check_bom_valid will silently flip every bom_validated field to False, and users will need to re-validate their entire BOM tree.

    This is effectively a breaking schema change to the hash algorithm. Consider documenting it as a migration note, or running a one-off task on startup to recompute and persist updated checksums so that existing valid BOMs are not incorrectly marked invalid.

  3. src/backend/InvenTree/part/test_bom_item.py, line 457-466 (link)

    assembly_2 BOM state not verified after item is moved back

    The test covers assembly thoroughly, but after bom_item.part = assembly_2 / bom_item.save(), it never checks that assembly_2.bom_validated is also set to False. Likewise, after restoring bom_item.part = assembly, assembly_2's BOM (now empty) should also be re-evaluated. A check(valid=False) call on assembly_2 at those points would provide full coverage of the dual-assembly update introduced in this PR.

Prompt To Fix All With AI
This is a comment left during a code review.
Path: src/backend/InvenTree/part/models.py
Line: 4089-4103

Comment:
**Part rename triggers spurious BOM invalidation**

`hash_fields()` now includes `'part'` and `'sub_part'`, which are FK fields. In `get_item_hash()`, `getattr(self, 'part')` returns the `Part` instance, and `str(Part_instance)` resolves to `f'{self.full_name} - {self.description}'` (see `Part.__str__`). This means renaming an assembly or sub-part will change the computed `get_bom_hash()` for every BOM that references it, causing `is_bom_valid()` to return `False` and `check_bom_valid` to subsequently flip `bom_validated = False` — even though the BOM structure itself is unchanged.

The intent of adding `'part'` and `'sub_part'` is clearly to fix delta detection (so that `any(f in deltas for f in self.hash_fields())` catches FK assignments like `bom_item.part = assembly_2`). But those same string names are also fed into the hash calculation and pick up the model's `__str__` value. Only `'part_id'` / `'sub_part_id'` should be used in the hash itself.

How can I resolve this? If you propose a fix, please make it concise.

---

This is a comment left during a code review.
Path: src/backend/InvenTree/part/models.py
Line: 4087-4103

Comment:
**Hash algorithm change invalidates all existing validated BOMs**

Adding `'part'` and `'sub_part'` to `hash_fields()` changes the output of `get_item_hash()` for every existing BOM line, which in turn changes `get_bom_hash()` for every assembly. After deployment, `is_bom_valid()` will return `False` for all previously validated BOMs (stored checksum no longer matches the new calculation). `check_bom_valid` will silently flip every `bom_validated` field to `False`, and users will need to re-validate their entire BOM tree.

This is effectively a breaking schema change to the hash algorithm. Consider documenting it as a migration note, or running a one-off task on startup to recompute and persist updated checksums so that existing valid BOMs are not incorrectly marked invalid.

How can I resolve this? If you propose a fix, please make it concise.

---

This is a comment left during a code review.
Path: src/backend/InvenTree/part/test_bom_item.py
Line: 457-466

Comment:
**`assembly_2` BOM state not verified after item is moved back**

The test covers `assembly` thoroughly, but after `bom_item.part = assembly_2` / `bom_item.save()`, it never checks that `assembly_2.bom_validated` is also set to `False`. Likewise, after restoring `bom_item.part = assembly`, `assembly_2`'s BOM (now empty) should also be re-evaluated. A `check(valid=False)` call on `assembly_2` at those points would provide full coverage of the dual-assembly update introduced in this PR.

How can I resolve this? If you propose a fix, please make it concise.

Reviews (1): Last reviewed commit: "[bug] BOM validation fixes (#11783)" | Re-trigger Greptile

* Ensure a new BOM item triggers check_bom_valid

* Ensure BOM validation is properly recomputed on a BOM item update

* Add unit tests

* Tweak unit tests

* Update 'clear_bom' method
@pull pull Bot locked and limited conversation to collaborators Apr 22, 2026
@pull pull Bot added the ⤵️ pull label Apr 22, 2026
@pull
pull Bot merged commit a94798d into Latitudes-Dev:master Apr 22, 2026
4 checks passed
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant