Skip to content

Commit 0e20e35

Browse files
authored
fix: preserve inventory dimensions when raw materials are reset (#54440)
* fix: preserve inventory dimensions when raw materials are reset * test: add test case
1 parent b4107b8 commit 0e20e35

7 files changed

Lines changed: 115 additions & 5 deletions

File tree

erpnext/patches.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -478,3 +478,4 @@ erpnext.patches.v16_0.depends_on_inv_dimensions
478478
erpnext.patches.v16_0.uom_category
479479
erpnext.patches.v16_0.merge_repost_settings_to_accounts_settings
480480
erpnext.patches.v16_0.set_root_type_in_account_categories
481+
erpnext.patches.v16_0.scr_inv_dimension
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import frappe
2+
3+
from erpnext.stock.doctype.inventory_dimension.inventory_dimension import get_inventory_dimensions
4+
5+
6+
def execute():
7+
for dimension in get_inventory_dimensions():
8+
if frappe.db.exists(
9+
"Custom Field",
10+
{
11+
"fieldname": dimension.source_fieldname,
12+
"dt": "Subcontracting Receipt Supplied Item",
13+
"reqd": 1,
14+
},
15+
):
16+
frappe.set_value(
17+
"Custom Field",
18+
{
19+
"fieldname": dimension.source_fieldname,
20+
"dt": "Subcontracting Receipt Supplied Item",
21+
"reqd": 1,
22+
},
23+
{"reqd": 0, "mandatory_depends_on": "eval:doc.reference_name"},
24+
)

erpnext/stock/doctype/inventory_dimension/inventory_dimension.py

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,13 @@ def get_dimension_fields(self, doctype=None):
169169
if label_start_with:
170170
label = f"{label_start_with} {self.dimension_name}"
171171

172+
mandatory_depends_on = self.mandatory_depends_on
173+
if self.reqd:
174+
if doctype == "Stock Entry Detail":
175+
mandatory_depends_on = "eval:doc.s_warehouse"
176+
elif doctype == "Subcontracting Receipt Supplied Item":
177+
mandatory_depends_on = "eval:doc.reference_name"
178+
172179
dimension_fields = [
173180
dict(
174181
fieldname="inventory_dimension",
@@ -186,11 +193,11 @@ def get_dimension_fields(self, doctype=None):
186193
depends_on="eval:doc.s_warehouse" if doctype == "Stock Entry Detail" else "",
187194
search_index=1,
188195
reqd=1
189-
if self.reqd and not self.mandatory_depends_on and doctype != "Stock Entry Detail"
196+
if self.reqd
197+
and not self.mandatory_depends_on
198+
and doctype not in ["Stock Entry Detail", "Subcontracting Receipt Supplied Item"]
190199
else 0,
191-
mandatory_depends_on="eval:doc.s_warehouse"
192-
if self.reqd and doctype == "Stock Entry Detail"
193-
else self.mandatory_depends_on,
200+
mandatory_depends_on=mandatory_depends_on,
194201
),
195202
]
196203

erpnext/stock/doctype/inventory_dimension/test_inventory_dimension.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -224,7 +224,6 @@ def test_check_mandatory_dimensions(self):
224224
)
225225
)
226226

227-
doc.load_from_db
228227
doc.reqd = 0
229228
doc.save()
230229

erpnext/subcontracting/doctype/subcontracting_receipt/subcontracting_receipt.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -435,6 +435,12 @@ frappe.ui.form.on("Subcontracting Receipt Item", {
435435
set_missing_values(frm);
436436
},
437437

438+
before_items_remove(frm, cdt, cdn) {
439+
const filtered_rows = frm.doc.supplied_items.filter((item) => item.reference_name !== cdn);
440+
frm.doc.supplied_items = filtered_rows;
441+
frm.refresh_field("supplied_items");
442+
},
443+
438444
items_delete(frm) {
439445
set_missing_values(frm);
440446
},

erpnext/subcontracting/doctype/subcontracting_receipt/subcontracting_receipt.py

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
from erpnext.controllers.subcontracting_controller import SubcontractingController
1717
from erpnext.setup.doctype.brand.brand import get_brand_defaults
1818
from erpnext.setup.doctype.item_group.item_group import get_item_group_defaults
19+
from erpnext.stock.doctype.inventory_dimension.inventory_dimension import get_inventory_dimensions
1920
from erpnext.stock.doctype.item.item import get_item_defaults
2021
from erpnext.stock.get_item_details import get_default_cost_center, get_default_expense_account
2122
from erpnext.stock.stock_ledger import get_valuation_rate
@@ -120,6 +121,7 @@ def onload(self):
120121
)
121122

122123
def before_validate(self):
124+
self.save_inventory_dimensions()
123125
super().before_validate()
124126
self.validate_items_qty()
125127
self.set_items_bom()
@@ -160,6 +162,7 @@ def validate(self):
160162

161163
self.set_supplied_items_expense_account()
162164
self.set_supplied_items_cost_center()
165+
self.set_supplied_items_inventory_dimensions()
163166

164167
def on_submit(self):
165168
self.validate_closed_subcontracting_order()
@@ -313,6 +316,22 @@ def set_supplied_items_cost_center(self):
313316
self.company,
314317
)
315318

319+
def set_supplied_items_inventory_dimensions(self):
320+
if hasattr(self, "inventory_dimensions") and (inventory_dimensions := get_inventory_dimensions()):
321+
for item in self.supplied_items:
322+
key = (
323+
item.reference_name,
324+
item.rm_item_code,
325+
item.main_item_code,
326+
item.batch_no,
327+
item.serial_no,
328+
)
329+
330+
for dimension in inventory_dimensions:
331+
dimension_values = self.inventory_dimensions.get(dimension.source_fieldname, {})
332+
if key in dimension_values:
333+
item.set(dimension.source_fieldname, dimension_values[key])
334+
316335
def set_supplied_items_expense_account(self):
317336
for item in self.supplied_items:
318337
if not item.expense_account:
@@ -329,6 +348,19 @@ def set_supplied_items_expense_account(self):
329348
get_brand_defaults(item.rm_item_code, self.company),
330349
)
331350

351+
def save_inventory_dimensions(self):
352+
if inventory_dimensions := get_inventory_dimensions():
353+
if not getattr(self, "inventory_dimensions", None):
354+
self.inventory_dimensions = {}
355+
356+
for dimension in inventory_dimensions:
357+
self.inventory_dimensions[dimension.source_fieldname] = {
358+
(d.reference_name, d.rm_item_code, d.main_item_code, d.batch_no, d.serial_no): d.get(
359+
dimension.source_fieldname
360+
)
361+
for d in self.supplied_items
362+
}
363+
332364
def reset_supplied_items(self):
333365
if (
334366
frappe.db.get_single_value("Buying Settings", "backflush_raw_materials_of_subcontract_based_on")

erpnext/subcontracting/doctype/subcontracting_receipt/test_subcontracting_receipt.py

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2035,6 +2035,47 @@ def test_over_receipt(self):
20352035
scr.submit()
20362036
frappe.flags["args"].pop("items", None)
20372037

2038+
def test_inventory_dimensions(self):
2039+
"""
2040+
The subcontracting controller resets the supplied items table on each save causing the inventory dimensions to be lost.
2041+
This test ensures that the inventory dimensions are retained on each save.
2042+
"""
2043+
from erpnext.stock.doctype.inventory_dimension.test_inventory_dimension import (
2044+
create_inventory_dimension,
2045+
)
2046+
2047+
inventory_dimension = create_inventory_dimension(
2048+
apply_to_all_doctypes=1,
2049+
dimension_name="Inv Site",
2050+
reference_document="Inv Site",
2051+
document_type="Inv Site",
2052+
)
2053+
2054+
inventory_dimension.reqd = 1
2055+
inventory_dimension.save()
2056+
2057+
set_backflush_based_on("BOM")
2058+
2059+
sco = get_subcontracting_order()
2060+
rm_items = get_rm_items(sco.supplied_items)
2061+
itemwise_details = make_stock_in_entry(rm_items=rm_items)
2062+
make_stock_transfer_entry(
2063+
sco_no=sco.name,
2064+
rm_items=rm_items,
2065+
itemwise_details=copy.deepcopy(itemwise_details),
2066+
)
2067+
scr = make_subcontracting_receipt(sco.name)
2068+
scr.items[0].inv_site = "Site 1"
2069+
scr.save()
2070+
2071+
scr.supplied_items[0].inv_site = "Site 1"
2072+
scr.save()
2073+
2074+
self.assertEqual(scr.supplied_items[0].inv_site, "Site 1")
2075+
2076+
inventory_dimension.reqd = 0
2077+
inventory_dimension.save()
2078+
20382079

20392080
def make_return_subcontracting_receipt(**args):
20402081
args = frappe._dict(args)

0 commit comments

Comments
 (0)