Skip to content

Commit 722dc8c

Browse files
fix: preserve inventory dimensions when raw materials are reset (backport #54440) (#54492)
* fix: preserve inventory dimensions when raw materials are reset (#54440) * fix: preserve inventory dimensions when raw materials are reset * test: add test case (cherry picked from commit 0e20e35) # Conflicts: # erpnext/patches.txt # erpnext/subcontracting/doctype/subcontracting_receipt/subcontracting_receipt.js # erpnext/subcontracting/doctype/subcontracting_receipt/test_subcontracting_receipt.py * chore: resolve conflicts * chore: resolve conflicts * chore: resolve conflicts --------- Co-authored-by: Mihir Kandoi <kandoimihir@gmail.com>
1 parent e0013f7 commit 722dc8c

7 files changed

Lines changed: 116 additions & 6 deletions

File tree

erpnext/patches.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -433,3 +433,4 @@ erpnext.patches.v15_0.replace_http_with_https_in_sales_partner
433433
erpnext.patches.v16_0.add_portal_redirects
434434
erpnext.patches.v16_0.update_order_qty_and_requested_qty_based_on_mr_and_po
435435
erpnext.patches.v16_0.depends_on_inv_dimensions
436+
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
@@ -166,6 +166,13 @@ def get_dimension_fields(self, doctype=None):
166166
if label_start_with:
167167
label = f"{label_start_with} {self.dimension_name}"
168168

169+
mandatory_depends_on = self.mandatory_depends_on
170+
if self.reqd:
171+
if doctype == "Stock Entry Detail":
172+
mandatory_depends_on = "eval:doc.s_warehouse"
173+
elif doctype == "Subcontracting Receipt Supplied Item":
174+
mandatory_depends_on = "eval:doc.reference_name"
175+
169176
dimension_fields = [
170177
dict(
171178
fieldname="inventory_dimension",
@@ -183,11 +190,11 @@ def get_dimension_fields(self, doctype=None):
183190
depends_on="eval:doc.s_warehouse" if doctype == "Stock Entry Detail" else "",
184191
search_index=1,
185192
reqd=1
186-
if self.reqd and not self.mandatory_depends_on and doctype != "Stock Entry Detail"
193+
if self.reqd
194+
and not self.mandatory_depends_on
195+
and doctype not in ["Stock Entry Detail", "Subcontracting Receipt Supplied Item"]
187196
else 0,
188-
mandatory_depends_on="eval:doc.s_warehouse"
189-
if self.reqd and doctype == "Stock Entry Detail"
190-
else self.mandatory_depends_on,
197+
mandatory_depends_on=mandatory_depends_on,
191198
),
192199
]
193200

erpnext/stock/doctype/inventory_dimension/test_inventory_dimension.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -234,7 +234,6 @@ def test_check_mandatory_dimensions(self):
234234
)
235235
)
236236

237-
doc.load_from_db
238237
doc.reqd = 0
239238
doc.save()
240239

erpnext/subcontracting/doctype/subcontracting_receipt/subcontracting_receipt.js

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -425,7 +425,13 @@ frappe.ui.form.on("Subcontracting Receipt Item", {
425425
set_missing_values(frm);
426426
},
427427

428-
items_delete: (frm) => {
428+
before_items_remove(frm, cdt, cdn) {
429+
const filtered_rows = frm.doc.supplied_items.filter((item) => item.reference_name !== cdn);
430+
frm.doc.supplied_items = filtered_rows;
431+
frm.refresh_field("supplied_items");
432+
},
433+
434+
items_delete(frm) {
429435
set_missing_values(frm);
430436
},
431437

erpnext/subcontracting/doctype/subcontracting_receipt/subcontracting_receipt.py

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
from erpnext.controllers.subcontracting_controller import SubcontractingController
1515
from erpnext.setup.doctype.brand.brand import get_brand_defaults
1616
from erpnext.setup.doctype.item_group.item_group import get_item_group_defaults
17+
from erpnext.stock.doctype.inventory_dimension.inventory_dimension import get_inventory_dimensions
1718
from erpnext.stock.doctype.item.item import get_item_defaults
1819
from erpnext.stock.get_item_details import get_default_cost_center, get_default_expense_account
1920
from erpnext.stock.stock_ledger import get_valuation_rate
@@ -118,6 +119,7 @@ def onload(self):
118119
)
119120

120121
def before_validate(self):
122+
self.save_inventory_dimensions()
121123
super().before_validate()
122124
self.validate_items_qty()
123125
self.set_items_bom()
@@ -158,6 +160,7 @@ def validate(self):
158160

159161
self.set_supplied_items_expense_account()
160162
self.set_supplied_items_cost_center()
163+
self.set_supplied_items_inventory_dimensions()
161164

162165
def on_submit(self):
163166
self.validate_closed_subcontracting_order()
@@ -289,6 +292,22 @@ def set_supplied_items_cost_center(self):
289292
self.company,
290293
)
291294

295+
def set_supplied_items_inventory_dimensions(self):
296+
if hasattr(self, "inventory_dimensions") and (inventory_dimensions := get_inventory_dimensions()):
297+
for item in self.supplied_items:
298+
key = (
299+
item.reference_name,
300+
item.rm_item_code,
301+
item.main_item_code,
302+
item.batch_no,
303+
item.serial_no,
304+
)
305+
306+
for dimension in inventory_dimensions:
307+
dimension_values = self.inventory_dimensions.get(dimension.source_fieldname, {})
308+
if key in dimension_values:
309+
item.set(dimension.source_fieldname, dimension_values[key])
310+
292311
def set_supplied_items_expense_account(self):
293312
for item in self.supplied_items:
294313
if not item.expense_account:
@@ -305,6 +324,19 @@ def set_supplied_items_expense_account(self):
305324
get_brand_defaults(item.rm_item_code, self.company),
306325
)
307326

327+
def save_inventory_dimensions(self):
328+
if inventory_dimensions := get_inventory_dimensions():
329+
if not getattr(self, "inventory_dimensions", None):
330+
self.inventory_dimensions = {}
331+
332+
for dimension in inventory_dimensions:
333+
self.inventory_dimensions[dimension.source_fieldname] = {
334+
(d.reference_name, d.rm_item_code, d.main_item_code, d.batch_no, d.serial_no): d.get(
335+
dimension.source_fieldname
336+
)
337+
for d in self.supplied_items
338+
}
339+
308340
def reset_supplied_items(self):
309341
if (
310342
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
@@ -2002,6 +2002,47 @@ def test_bom_required_qty_validation_based_on_transfer(self):
20022002

20032003
self.assertRaises(BOMQuantityError, scr.submit)
20042004

2005+
def test_inventory_dimensions(self):
2006+
"""
2007+
The subcontracting controller resets the supplied items table on each save causing the inventory dimensions to be lost.
2008+
This test ensures that the inventory dimensions are retained on each save.
2009+
"""
2010+
from erpnext.stock.doctype.inventory_dimension.test_inventory_dimension import (
2011+
create_inventory_dimension,
2012+
)
2013+
2014+
inventory_dimension = create_inventory_dimension(
2015+
apply_to_all_doctypes=1,
2016+
dimension_name="Inv Site",
2017+
reference_document="Inv Site",
2018+
document_type="Inv Site",
2019+
)
2020+
2021+
inventory_dimension.reqd = 1
2022+
inventory_dimension.save()
2023+
2024+
set_backflush_based_on("BOM")
2025+
2026+
sco = get_subcontracting_order()
2027+
rm_items = get_rm_items(sco.supplied_items)
2028+
itemwise_details = make_stock_in_entry(rm_items=rm_items)
2029+
make_stock_transfer_entry(
2030+
sco_no=sco.name,
2031+
rm_items=rm_items,
2032+
itemwise_details=copy.deepcopy(itemwise_details),
2033+
)
2034+
scr = make_subcontracting_receipt(sco.name)
2035+
scr.items[0].inv_site = "Site 1"
2036+
scr.save()
2037+
2038+
scr.supplied_items[0].inv_site = "Site 1"
2039+
scr.save()
2040+
2041+
self.assertEqual(scr.supplied_items[0].inv_site, "Site 1")
2042+
2043+
inventory_dimension.reqd = 0
2044+
inventory_dimension.save()
2045+
20052046

20062047
def make_return_subcontracting_receipt(**args):
20072048
args = frappe._dict(args)

0 commit comments

Comments
 (0)