mirror of
https://github.com/frappe/erpnext.git
synced 2026-05-01 12:38:27 +00:00
fix: preserve inventory dimensions when raw materials are reset (backport #54440) (backport #54493) (#54513)
* fix: preserve inventory dimensions when raw materials are reset (backport #54440) (#54493) 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 commit0e20e35842) Co-authored-by: Mihir Kandoi <kandoimihir@gmail.com> (cherry picked from commit456e99b352) # Conflicts: # erpnext/patches.txt * chore: resolve conflicts --------- Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com> Co-authored-by: Mihir Kandoi <kandoimihir@gmail.com>
This commit is contained in:
@@ -476,3 +476,4 @@ erpnext.patches.v16_0.co_by_product_patch
|
|||||||
erpnext.patches.v16_0.depends_on_inv_dimensions
|
erpnext.patches.v16_0.depends_on_inv_dimensions
|
||||||
erpnext.patches.v16_0.uom_category
|
erpnext.patches.v16_0.uom_category
|
||||||
erpnext.patches.v16_0.merge_repost_settings_to_accounts_settings
|
erpnext.patches.v16_0.merge_repost_settings_to_accounts_settings
|
||||||
|
erpnext.patches.v16_0.scr_inv_dimension
|
||||||
|
|||||||
24
erpnext/patches/v16_0/scr_inv_dimension.py
Normal file
24
erpnext/patches/v16_0/scr_inv_dimension.py
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
import frappe
|
||||||
|
|
||||||
|
from erpnext.stock.doctype.inventory_dimension.inventory_dimension import get_inventory_dimensions
|
||||||
|
|
||||||
|
|
||||||
|
def execute():
|
||||||
|
for dimension in get_inventory_dimensions():
|
||||||
|
if frappe.db.exists(
|
||||||
|
"Custom Field",
|
||||||
|
{
|
||||||
|
"fieldname": dimension.source_fieldname,
|
||||||
|
"dt": "Subcontracting Receipt Supplied Item",
|
||||||
|
"reqd": 1,
|
||||||
|
},
|
||||||
|
):
|
||||||
|
frappe.set_value(
|
||||||
|
"Custom Field",
|
||||||
|
{
|
||||||
|
"fieldname": dimension.source_fieldname,
|
||||||
|
"dt": "Subcontracting Receipt Supplied Item",
|
||||||
|
"reqd": 1,
|
||||||
|
},
|
||||||
|
{"reqd": 0, "mandatory_depends_on": "eval:doc.reference_name"},
|
||||||
|
)
|
||||||
@@ -167,6 +167,13 @@ class InventoryDimension(Document):
|
|||||||
if label_start_with:
|
if label_start_with:
|
||||||
label = f"{label_start_with} {self.dimension_name}"
|
label = f"{label_start_with} {self.dimension_name}"
|
||||||
|
|
||||||
|
mandatory_depends_on = self.mandatory_depends_on
|
||||||
|
if self.reqd:
|
||||||
|
if doctype == "Stock Entry Detail":
|
||||||
|
mandatory_depends_on = "eval:doc.s_warehouse"
|
||||||
|
elif doctype == "Subcontracting Receipt Supplied Item":
|
||||||
|
mandatory_depends_on = "eval:doc.reference_name"
|
||||||
|
|
||||||
dimension_fields = [
|
dimension_fields = [
|
||||||
dict(
|
dict(
|
||||||
fieldname="inventory_dimension",
|
fieldname="inventory_dimension",
|
||||||
@@ -184,11 +191,11 @@ class InventoryDimension(Document):
|
|||||||
depends_on="eval:doc.s_warehouse" if doctype == "Stock Entry Detail" else "",
|
depends_on="eval:doc.s_warehouse" if doctype == "Stock Entry Detail" else "",
|
||||||
search_index=1,
|
search_index=1,
|
||||||
reqd=1
|
reqd=1
|
||||||
if self.reqd and not self.mandatory_depends_on and doctype != "Stock Entry Detail"
|
if self.reqd
|
||||||
|
and not self.mandatory_depends_on
|
||||||
|
and doctype not in ["Stock Entry Detail", "Subcontracting Receipt Supplied Item"]
|
||||||
else 0,
|
else 0,
|
||||||
mandatory_depends_on="eval:doc.s_warehouse"
|
mandatory_depends_on=mandatory_depends_on,
|
||||||
if self.reqd and doctype == "Stock Entry Detail"
|
|
||||||
else self.mandatory_depends_on,
|
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|||||||
@@ -225,7 +225,6 @@ class TestInventoryDimension(ERPNextTestSuite):
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
doc.load_from_db
|
|
||||||
doc.reqd = 0
|
doc.reqd = 0
|
||||||
doc.save()
|
doc.save()
|
||||||
|
|
||||||
|
|||||||
@@ -435,6 +435,12 @@ frappe.ui.form.on("Subcontracting Receipt Item", {
|
|||||||
set_missing_values(frm);
|
set_missing_values(frm);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
before_items_remove(frm, cdt, cdn) {
|
||||||
|
const filtered_rows = frm.doc.supplied_items.filter((item) => item.reference_name !== cdn);
|
||||||
|
frm.doc.supplied_items = filtered_rows;
|
||||||
|
frm.refresh_field("supplied_items");
|
||||||
|
},
|
||||||
|
|
||||||
items_delete(frm) {
|
items_delete(frm) {
|
||||||
set_missing_values(frm);
|
set_missing_values(frm);
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ from erpnext.buying.utils import check_on_hold_or_closed_status
|
|||||||
from erpnext.controllers.subcontracting_controller import SubcontractingController
|
from erpnext.controllers.subcontracting_controller import SubcontractingController
|
||||||
from erpnext.setup.doctype.brand.brand import get_brand_defaults
|
from erpnext.setup.doctype.brand.brand import get_brand_defaults
|
||||||
from erpnext.setup.doctype.item_group.item_group import get_item_group_defaults
|
from erpnext.setup.doctype.item_group.item_group import get_item_group_defaults
|
||||||
|
from erpnext.stock.doctype.inventory_dimension.inventory_dimension import get_inventory_dimensions
|
||||||
from erpnext.stock.doctype.item.item import get_item_defaults
|
from erpnext.stock.doctype.item.item import get_item_defaults
|
||||||
from erpnext.stock.get_item_details import get_default_cost_center, get_default_expense_account
|
from erpnext.stock.get_item_details import get_default_cost_center, get_default_expense_account
|
||||||
from erpnext.stock.stock_ledger import get_valuation_rate
|
from erpnext.stock.stock_ledger import get_valuation_rate
|
||||||
@@ -119,6 +120,7 @@ class SubcontractingReceipt(SubcontractingController):
|
|||||||
)
|
)
|
||||||
|
|
||||||
def before_validate(self):
|
def before_validate(self):
|
||||||
|
self.save_inventory_dimensions()
|
||||||
super().before_validate()
|
super().before_validate()
|
||||||
self.validate_items_qty()
|
self.validate_items_qty()
|
||||||
self.set_items_bom()
|
self.set_items_bom()
|
||||||
@@ -159,6 +161,7 @@ class SubcontractingReceipt(SubcontractingController):
|
|||||||
|
|
||||||
self.set_supplied_items_expense_account()
|
self.set_supplied_items_expense_account()
|
||||||
self.set_supplied_items_cost_center()
|
self.set_supplied_items_cost_center()
|
||||||
|
self.set_supplied_items_inventory_dimensions()
|
||||||
|
|
||||||
def on_submit(self):
|
def on_submit(self):
|
||||||
self.validate_closed_subcontracting_order()
|
self.validate_closed_subcontracting_order()
|
||||||
@@ -312,6 +315,22 @@ class SubcontractingReceipt(SubcontractingController):
|
|||||||
self.company,
|
self.company,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def set_supplied_items_inventory_dimensions(self):
|
||||||
|
if hasattr(self, "inventory_dimensions") and (inventory_dimensions := get_inventory_dimensions()):
|
||||||
|
for item in self.supplied_items:
|
||||||
|
key = (
|
||||||
|
item.reference_name,
|
||||||
|
item.rm_item_code,
|
||||||
|
item.main_item_code,
|
||||||
|
item.batch_no,
|
||||||
|
item.serial_no,
|
||||||
|
)
|
||||||
|
|
||||||
|
for dimension in inventory_dimensions:
|
||||||
|
dimension_values = self.inventory_dimensions.get(dimension.source_fieldname, {})
|
||||||
|
if key in dimension_values:
|
||||||
|
item.set(dimension.source_fieldname, dimension_values[key])
|
||||||
|
|
||||||
def set_supplied_items_expense_account(self):
|
def set_supplied_items_expense_account(self):
|
||||||
for item in self.supplied_items:
|
for item in self.supplied_items:
|
||||||
if not item.expense_account:
|
if not item.expense_account:
|
||||||
@@ -328,6 +347,19 @@ class SubcontractingReceipt(SubcontractingController):
|
|||||||
get_brand_defaults(item.rm_item_code, self.company),
|
get_brand_defaults(item.rm_item_code, self.company),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def save_inventory_dimensions(self):
|
||||||
|
if inventory_dimensions := get_inventory_dimensions():
|
||||||
|
if not getattr(self, "inventory_dimensions", None):
|
||||||
|
self.inventory_dimensions = {}
|
||||||
|
|
||||||
|
for dimension in inventory_dimensions:
|
||||||
|
self.inventory_dimensions[dimension.source_fieldname] = {
|
||||||
|
(d.reference_name, d.rm_item_code, d.main_item_code, d.batch_no, d.serial_no): d.get(
|
||||||
|
dimension.source_fieldname
|
||||||
|
)
|
||||||
|
for d in self.supplied_items
|
||||||
|
}
|
||||||
|
|
||||||
def reset_supplied_items(self):
|
def reset_supplied_items(self):
|
||||||
if (
|
if (
|
||||||
frappe.db.get_single_value("Buying Settings", "backflush_raw_materials_of_subcontract_based_on")
|
frappe.db.get_single_value("Buying Settings", "backflush_raw_materials_of_subcontract_based_on")
|
||||||
|
|||||||
@@ -2036,6 +2036,47 @@ class TestSubcontractingReceipt(ERPNextTestSuite):
|
|||||||
scr.submit()
|
scr.submit()
|
||||||
frappe.flags["args"].pop("items", None)
|
frappe.flags["args"].pop("items", None)
|
||||||
|
|
||||||
|
def test_inventory_dimensions(self):
|
||||||
|
"""
|
||||||
|
The subcontracting controller resets the supplied items table on each save causing the inventory dimensions to be lost.
|
||||||
|
This test ensures that the inventory dimensions are retained on each save.
|
||||||
|
"""
|
||||||
|
from erpnext.stock.doctype.inventory_dimension.test_inventory_dimension import (
|
||||||
|
create_inventory_dimension,
|
||||||
|
)
|
||||||
|
|
||||||
|
inventory_dimension = create_inventory_dimension(
|
||||||
|
apply_to_all_doctypes=1,
|
||||||
|
dimension_name="Inv Site",
|
||||||
|
reference_document="Inv Site",
|
||||||
|
document_type="Inv Site",
|
||||||
|
)
|
||||||
|
|
||||||
|
inventory_dimension.reqd = 1
|
||||||
|
inventory_dimension.save()
|
||||||
|
|
||||||
|
set_backflush_based_on("BOM")
|
||||||
|
|
||||||
|
sco = get_subcontracting_order()
|
||||||
|
rm_items = get_rm_items(sco.supplied_items)
|
||||||
|
itemwise_details = make_stock_in_entry(rm_items=rm_items)
|
||||||
|
make_stock_transfer_entry(
|
||||||
|
sco_no=sco.name,
|
||||||
|
rm_items=rm_items,
|
||||||
|
itemwise_details=copy.deepcopy(itemwise_details),
|
||||||
|
)
|
||||||
|
scr = make_subcontracting_receipt(sco.name)
|
||||||
|
scr.items[0].inv_site = "Site 1"
|
||||||
|
scr.save()
|
||||||
|
|
||||||
|
scr.supplied_items[0].inv_site = "Site 1"
|
||||||
|
scr.save()
|
||||||
|
|
||||||
|
self.assertEqual(scr.supplied_items[0].inv_site, "Site 1")
|
||||||
|
|
||||||
|
inventory_dimension.reqd = 0
|
||||||
|
inventory_dimension.save()
|
||||||
|
|
||||||
|
|
||||||
def make_return_subcontracting_receipt(**args):
|
def make_return_subcontracting_receipt(**args):
|
||||||
args = frappe._dict(args)
|
args = frappe._dict(args)
|
||||||
|
|||||||
Reference in New Issue
Block a user