Versions
- ERPNext: 16.29.0
- Frappe: 16.28.0
- Perpetual inventory: enabled, valuation method FIFO
- No BOMs in the system (production is recorded directly as Stock Entries)
Summary
In v15 we could tick “Is Scrap Item” on co-product / scrap rows of a Manufacture Stock Entry, and the finished-good rate was computed as a residual so that value_difference came out to 0.
In v16 that checkbox has been renamed to is_legacy_scrap_item and made read-only, and a new type Select field (Co-Product / By-Product / Scrap / Additional Finished Good) has been introduced in its place.
The problem: the finished-good valuation still reads is_legacy_scrap_item, not type. So a multi-output Manufacture entry built through the UI can no longer be balanced, because the only field that affects the calculation cannot be set from the UI.
Field metadata in v16 (Stock Entry Detail)
| Field | read_only |
depends_on |
|---|---|---|
is_legacy_scrap_item |
1 | `is_legacy_sc |
type |
0 | eval:parent.purpose == "Manufacture" && doc.t_warehouse && !doc.is_finished_item && !doc.is_legacy_scrap_item |
set_basic_rate_manually |
0 | eval:parent.purpose==="Repack" && doc.t_warehouse |
Two consequences:
is_legacy_scrap_itemis read-only and itsdepends_onrefers to itself, so it is only rendered on rows where it is
already1. It can never be newly ticked from tset_basic_rate_manuallyis only rendered forRepack, so on a Manufacture entry there is also no way to override the
computed rate manually.
is_scrap_item no longer exists on the doctype
The calculation
get_basic_rate_for_manufactured_item() compute
FG rate = (total_outgoing_value − scrap_items_cost) / fg_qty
scrap_items_cost = sum(basic_amount for rows where is_legacy_scrap_item == 1)
type does not appear in this sum. As far as we source, type only influences valuation viabom_secondary_item / cost_allocation_per, which requires a BOM. With no BOM, setting type = Scrap has no effect on
valuation at all.
Steps to reproduce
Create a Manufacture Stock Entry with three rows
| Row | Warehouse | Item | Qty | Basic Rate |
|---|---|---|---|---|
| 1 | Source | A | 100 | 100.00 |
| 2 | Target | B (co-product) | 20 | 50.00 |
| 3 | Target | C (finished good, `is_finished_it |
Case 1 — is_legacy_scrap_item = 1 on row 2y unlocking the field)
scrap_items_cost = 1,000
FG rate = (10,000 − 1,000) / 80 = 112.50
incoming = 1,000 + 9,000 = 10,000
outgoing = 10,000
value_difference = 0.00 ✅
**Case 2 — type = "Scrap" on row 2, `is_legacyUI allows)
scrap_items_cost = 0 ← type not counted
FG rate = (10,000 − 0) / 80 = 125.00
incoming = 1,000 + 10,000 = 11,000
outgoing = 10,000
value_difference = 1,000.00 ❌
The difference is exactly the total of the co-pris counted twice: once in their own rows and again inside the finished good’s residual.
What we verified
-
A/B test on a test instance. We exposed
is_legacy_scrap_itemwith a Client Script and toggled only that one field on
the same document. Ticking it → difference 0. Une = Scrap` instead → difference reappears. Noother change. -
The field itself still works correctly in v16. On our production instance, 71 multi-output Manufacture entries created
via the REST API (withis_legacy_scrap_item = 1*and submitted** from the UI by other users afterthe v16 upgrade. In all 71, the flag survived andvalue_difference` stayed 0. So the server-side behaviour is intact — only UI
access to the field has been removed. -
The only way to get 0 from the UI on a mul co-product’s rate to
0, which balances theaccounts but assigns the co-product a zero valuation and pushes its entire cost onto the finished good. That is not an
acceptable result.
Current workaround
A Client Script on Stock Entry re-exposes the fi
frappe.ui.form.on('Stock Entry', {
refresh(frm) {
const grid = frm.fields_dict.items && frm.fields_dict.items.grid;
if (!grid) return;
grid.update_docfield_property('is_legacy_scrap_item', 'read_only', 0);
grid.update_docfield_property('is_legacy');
grid.update_docfield_property('is_legacy_scrap_item', 'hidden', 0);
frm.refresh_field('items');
}
});
Note that Customize Form cannot be used for this — it rejects the change with “You cannot unset ‘Read Only’ for field Is
Legacy Scrap Item”.
Questions
- Is
typeintended to replace `is_legacy_scravaluation, and is it a known gap that it currently does not? - Is a BOM now mandatory for co-product / scrapthere a supported path for shop-floor productionthat is recorded directly as Stock Entries without BOMs?
- If
is_legacy_scrap_itemis still the field should it remain read-only in the UI? Right nowthe only field that affects valuation is the one users cannot set.
Happy to share document JSON or run further tests if that helps.