-
Notifications
You must be signed in to change notification settings - Fork 9.8k
feat: phantom bom #50351
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: develop
Are you sure you want to change the base?
feat: phantom bom #50351
Conversation
…k order/manufacturing
0d5ff3c to
bdd297a
Compare
📝 WalkthroughWalkthroughThis PR adds native Phantom BOM support across manufacturing: introduces Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes
Possibly related PRs
Suggested labels
Suggested reviewers
Pre-merge checks and finishing touches❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing touches🧪 Generate unit tests (beta)
📜 Recent review detailsConfiguration used: Path: .coderabbit.yml Review profile: CHILL Plan: Pro 📒 Files selected for processing (1)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (6)
🔇 Additional comments (1)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 2
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
erpnext/manufacturing/doctype/bom_creator/bom_creator.py (1)
333-338: Scrap allowance flips off for every non-phantom row.
item.get("is_phantom_item")frequently arrives as the string"0", which is truthy in Python.not "0"therefore evaluates toFalse, so every normal component ends up withallow_scrap_items = 0. Cast the flag first so only actual phantom rows disable scrap.item_args.update( { "bom_no": bom_no, "allow_alternative_item": 1, - "allow_scrap_items": not item.get("is_phantom_item"), + "allow_scrap_items": not cint(item.get("is_phantom_item")), "include_item_in_manufacturing": 1, } )
📜 Review details
Configuration used: Path: .coderabbit.yml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (20)
erpnext/controllers/subcontracting_controller.py(4 hunks)erpnext/controllers/tests/test_subcontracting_controller.py(4 hunks)erpnext/manufacturing/doctype/bom/bom.js(2 hunks)erpnext/manufacturing/doctype/bom/bom.json(12 hunks)erpnext/manufacturing/doctype/bom/bom.py(11 hunks)erpnext/manufacturing/doctype/bom/test_bom.py(4 hunks)erpnext/manufacturing/doctype/bom_creator/bom_creator.py(5 hunks)erpnext/manufacturing/doctype/bom_creator_item/bom_creator_item.json(4 hunks)erpnext/manufacturing/doctype/bom_creator_item/bom_creator_item.py(1 hunks)erpnext/manufacturing/doctype/bom_item/bom_item.json(5 hunks)erpnext/manufacturing/doctype/bom_item/bom_item.py(1 hunks)erpnext/manufacturing/doctype/production_plan/production_plan.py(1 hunks)erpnext/manufacturing/doctype/production_plan/test_production_plan.py(1 hunks)erpnext/manufacturing/doctype/routing/routing.js(1 hunks)erpnext/manufacturing/doctype/work_order/test_work_order.py(1 hunks)erpnext/manufacturing/report/bom_explorer/bom_explorer.py(3 hunks)erpnext/manufacturing/report/bom_stock_calculated/bom_stock_calculated.py(3 hunks)erpnext/manufacturing/report/bom_stock_report/bom_stock_report.py(2 hunks)erpnext/manufacturing/report/bom_stock_report/test_bom_stock_report.py(1 hunks)erpnext/public/js/bom_configurator/bom_configurator.bundle.js(9 hunks)
🧰 Additional context used
🧠 Learnings (3)
📚 Learning: 2025-09-30T11:04:46.510Z
Learnt from: rohitwaghchaure
Repo: frappe/erpnext PR: 49766
File: erpnext/manufacturing/doctype/production_plan/production_plan.py:1717-1717
Timestamp: 2025-09-30T11:04:46.510Z
Learning: In the Production Plan's `get_items_for_material_requests` function in `erpnext/manufacturing/doctype/production_plan/production_plan.py`, always use `data.get("sales_order")` instead of `doc.get("sales_order")` when iterating over `po_items`. This ensures raw materials are correctly grouped by each production item's respective Sales Order, not a global document-level Sales Order.
Applied to files:
erpnext/manufacturing/doctype/production_plan/production_plan.py
📚 Learning: 2025-10-17T14:11:06.959Z
Learnt from: sagarvora
Repo: frappe/erpnext PR: 50155
File: erpnext/controllers/accounts_controller.py:2992-3005
Timestamp: 2025-10-17T14:11:06.959Z
Learning: In ERPNext, item child doctypes (like "Sales Invoice Item", "Delivery Note Item", etc.) have exactly one non-custom Link field that references their parent transaction doctype (like "Sales Order", "Purchase Order", etc.). This is a schema design pattern that can be relied upon when determining reference fields for mapping logic.
Applied to files:
erpnext/manufacturing/doctype/bom_creator_item/bom_creator_item.pyerpnext/manufacturing/doctype/bom_item/bom_item.json
📚 Learning: 2025-08-01T11:04:59.343Z
Learnt from: karm1000
Repo: frappe/erpnext PR: 48865
File: erpnext/accounts/doctype/purchase_invoice/purchase_invoice.json:1657-1664
Timestamp: 2025-08-01T11:04:59.343Z
Learning: In ERPNext/Frappe framework, virtual fields (marked with "is_virtual": 1) are always read-only by default and do not require an explicit "read_only": 1 property in their JSON definition.
Applied to files:
erpnext/manufacturing/doctype/bom/bom.jsonerpnext/manufacturing/doctype/bom_creator_item/bom_creator_item.json
🧬 Code graph analysis (6)
erpnext/manufacturing/doctype/production_plan/test_production_plan.py (2)
erpnext/manufacturing/doctype/bom/test_bom.py (1)
create_tree_for_phantom_bom_tests(914-923)erpnext/manufacturing/doctype/production_plan/production_plan.py (3)
get_sub_assembly_items(999-1066)get_sub_assembly_items(1840-1911)get_items_for_material_requests(1583-1771)
erpnext/manufacturing/report/bom_stock_report/bom_stock_report.py (1)
erpnext/manufacturing/report/bom_stock_calculated/bom_stock_calculated.py (1)
explode_phantom_boms(154-166)
erpnext/manufacturing/doctype/bom/bom.py (2)
erpnext/stock/doctype/stock_entry/stock_entry.js (6)
d(340-373)d(394-394)d(696-699)d(714-714)fields(620-620)fields(654-685)erpnext/manufacturing/doctype/bom/bom.js (4)
qty(525-525)fields(97-97)fields(307-307)fields(979-979)
erpnext/manufacturing/report/bom_stock_calculated/bom_stock_calculated.py (1)
erpnext/manufacturing/report/bom_stock_report/bom_stock_report.py (1)
explode_phantom_boms(93-107)
erpnext/manufacturing/doctype/work_order/test_work_order.py (1)
erpnext/manufacturing/doctype/bom/test_bom.py (1)
create_tree_for_phantom_bom_tests(914-923)
erpnext/controllers/tests/test_subcontracting_controller.py (1)
erpnext/manufacturing/doctype/bom/test_bom.py (1)
create_tree_for_phantom_bom_tests(914-923)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (6)
- GitHub Check: Python Unit Tests (2)
- GitHub Check: Python Unit Tests (3)
- GitHub Check: Python Unit Tests (1)
- GitHub Check: Python Unit Tests (4)
- GitHub Check: Patch Test
- GitHub Check: Summary
🔇 Additional comments (16)
erpnext/manufacturing/doctype/bom_creator_item/bom_creator_item.py (1)
28-28: Type hints cover phantom flag nicelyGood to see the TYPE_CHECKING stub exposing
is_phantom_item; it keeps our static analysis aligned with the new phantom payloads.erpnext/manufacturing/doctype/bom_item/bom_item.py (1)
28-28: Consistent phantom typingMatching the BOM item stub with
is_phantom_itemkeeps downstream typing accurate—thanks for keeping these in sync.erpnext/manufacturing/doctype/work_order/test_work_order.py (1)
3273-3279: Nice coverage for phantom work ordersAppreciate the focused fixture reuse; validating
required_itemsagainst the phantom tree guards the multi-level explosion path well.erpnext/manufacturing/doctype/production_plan/test_production_plan.py (1)
2417-2440: Production plan phantom flow well exercisedGreat to see the production-plan side validated—checking both sub-assembly entries and MR item flattening should catch regressions in phantom handling.
erpnext/public/js/bom_configurator/bom_configurator.bundle.js (1)
143-189: UI wiring for phantom nodes looks solidThe phantom-aware toolbar actions and modal plumbing (including the inverted stock filter) align with backend expectations—thanks for keeping the UX consistent.
erpnext/manufacturing/doctype/bom_item/bom_item.json (2)
45-46: LGTM! Well-structured phantom item field.The new
is_phantom_itemfield is properly configured as read-only with appropriate default value, correctly positioned in field order afteris_sub_assembly_item.Also applies to: 318-324
85-85: Field dependencies properly enforce phantom item semantics.The dependency logic correctly ensures:
- Phantom items must have a BOM reference (
mandatory_depends_on)- Phantom items cannot be sourced by supplier (hidden via
depends_on)do_not_explodeis read-only for phantom items (enforces explosion)is_sub_assembly_itemis hidden to avoid semantic confusionAlso applies to: 283-283, 293-293, 311-311
erpnext/manufacturing/doctype/bom/bom.py (7)
138-138: LGTM! Type annotation follows framework conventions.
451-463: Phantom item propagation and explosion enforcement is correct.The logic properly:
- Fetches
is_phantom_bomfrom the linked BOM and propagates to the item- Forces
do_not_explode = 0for phantom items to ensure multi-level explosionThis correctly implements the core phantom BOM requirement.
491-493: Phantom items correctly use BOM-based costing.The condition ensures phantom items always derive their rate from the BOM unit cost rather than item valuation, which is correct since phantoms are logical groupings without independent inventory valuation.
894-894: Phantom item integration in cost calculation is sound.Including
is_phantom_itemalongsideis_stock_itemin rate recalculation ensures phantom items receive proper BOM-based costing while maintaining the existing stock item logic.Also applies to: 905-905
1284-1327: SQL modifications correctly include phantom items in BOM explosion.The query logic ensures phantom items are included regardless of
include_non_stock_itemssetting:
- Line 1319:
or bom_item.is_phantom_itemensures phantoms are always fetched- Line 1324: Necessary fields (
is_phantom_item,bom_no) are selected for expansionThis enables proper multi-level explosion of phantom BOMs.
1412-1412: LGTM! Field addition enables phantom item visibility in BOM tree.
1334-1345: Recursion in phantom item expansion is protected by validation.The recursive expansion of phantom items at lines 1334-1345 is safe because
check_recursion()(called during BOM save) prevents cycles from being stored in the database. Since only acyclic BOM structures can exist, the runtime recursion cannot loop infinitely. Practical nesting depths are shallow (typically 5-10 levels), and stack limits are not a concern.Adding a clarifying comment about this validation-based protection would improve code maintainability.
erpnext/manufacturing/doctype/bom/bom.json (2)
19-19: LGTM! Phantom BOM field properly defined.The field is correctly positioned in the Production Item tab alongside other BOM-level configuration options.
Also applies to: 674-679
205-205: Field dependencies correctly enforce phantom BOM constraints.The UI properly hides sections that don't apply to phantom BOMs:
- Operations, scrap, and quality inspection (phantoms aren't physically produced)
- Website sections (phantoms are internal logical groupings)
- Project linkage (phantoms are components, not work order targets)
Notably,
raw_material_costremains visible, which is correct since phantom BOMs still require material cost calculation for explosion.Also applies to: 298-298, 316-316, 331-331, 344-344, 361-361, 390-390, 438-438, 548-548, 583-583
erpnext/manufacturing/report/bom_stock_calculated/bom_stock_calculated.py
Show resolved
Hide resolved
erpnext/manufacturing/report/bom_stock_report/bom_stock_report.py
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
📜 Review details
Configuration used: Path: .coderabbit.yml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (5)
erpnext/manufacturing/doctype/bom/bom.py(12 hunks)erpnext/manufacturing/doctype/production_plan/production_plan.py(10 hunks)erpnext/manufacturing/doctype/production_plan/test_production_plan.py(1 hunks)erpnext/manufacturing/report/bom_stock_calculated/bom_stock_calculated.py(5 hunks)erpnext/manufacturing/report/bom_stock_report/bom_stock_report.py(3 hunks)
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-09-30T11:04:46.510Z
Learnt from: rohitwaghchaure
Repo: frappe/erpnext PR: 49766
File: erpnext/manufacturing/doctype/production_plan/production_plan.py:1717-1717
Timestamp: 2025-09-30T11:04:46.510Z
Learning: In the Production Plan's `get_items_for_material_requests` function in `erpnext/manufacturing/doctype/production_plan/production_plan.py`, always use `data.get("sales_order")` instead of `doc.get("sales_order")` when iterating over `po_items`. This ensures raw materials are correctly grouped by each production item's respective Sales Order, not a global document-level Sales Order.
Applied to files:
erpnext/manufacturing/doctype/production_plan/production_plan.py
🧬 Code graph analysis (4)
erpnext/manufacturing/report/bom_stock_report/bom_stock_report.py (2)
erpnext/manufacturing/doctype/bom/bom.py (1)
BOM(102-1143)erpnext/manufacturing/report/bom_stock_calculated/bom_stock_calculated.py (1)
explode_phantom_boms(163-185)
erpnext/manufacturing/doctype/production_plan/production_plan.py (2)
erpnext/controllers/queries.py (1)
bom(280-307)erpnext/manufacturing/doctype/bom/bom.py (1)
is_sub_assembly_item(756-764)
erpnext/manufacturing/doctype/production_plan/test_production_plan.py (2)
erpnext/manufacturing/doctype/bom/test_bom.py (1)
create_tree_for_phantom_bom_tests(914-923)erpnext/manufacturing/doctype/production_plan/production_plan.py (2)
get_sub_assembly_items(999-1066)get_sub_assembly_items(1863-1936)
erpnext/manufacturing/report/bom_stock_calculated/bom_stock_calculated.py (1)
erpnext/manufacturing/report/bom_stock_report/bom_stock_report.py (1)
explode_phantom_boms(95-106)
🪛 Ruff (0.14.3)
erpnext/manufacturing/doctype/bom/bom.py
1403-1403: Unused function argument: is_root
(ARG001)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (6)
- GitHub Check: Python Unit Tests (2)
- GitHub Check: Python Unit Tests (3)
- GitHub Check: Python Unit Tests (1)
- GitHub Check: Python Unit Tests (4)
- GitHub Check: Patch Test
- GitHub Check: Summary
|
@mihir-kandoi Please add screenshots or videos for better to understand this feature. |
closes #48472
https://docs.frappe.io/erpnext/user/manual/en/bill-of-materials