fix: delete custom fields on deletion of inventory dimension
diff --git a/erpnext/controllers/stock_controller.py b/erpnext/controllers/stock_controller.py
index e27718a..440271c 100644
--- a/erpnext/controllers/stock_controller.py
+++ b/erpnext/controllers/stock_controller.py
@@ -374,9 +374,24 @@
def update_inventory_dimensions(self, row, sl_dict) -> None:
dimensions = get_evaluated_inventory_dimension(row, sl_dict, parent_doc=self)
for dimension in dimensions:
- if dimension and row.get(dimension.source_fieldname):
+ if not dimension:
+ continue
+
+ if row.get(dimension.source_fieldname):
sl_dict[dimension.target_fieldname] = row.get(dimension.source_fieldname)
+ if not sl_dict.get(dimension.target_fieldname) and dimension.fetch_from_parent:
+ sl_dict[dimension.target_fieldname] = self.get(dimension.fetch_from_parent)
+
+ # Get value based on doctype name
+ if not sl_dict.get(dimension.target_fieldname):
+ fieldname = frappe.get_cached_value(
+ "DocField", {"parent": self.doctype, "options": dimension.fetch_from_parent}, "fieldname"
+ )
+
+ if fieldname and self.get(fieldname):
+ sl_dict[dimension.target_fieldname] = self.get(fieldname)
+
def make_sl_entries(self, sl_entries, allow_negative_stock=False, via_landed_cost_voucher=False):
from erpnext.stock.stock_ledger import make_sl_entries
diff --git a/erpnext/stock/doctype/inventory_dimension/inventory_dimension.js b/erpnext/stock/doctype/inventory_dimension/inventory_dimension.js
index 91a21f4..07cb73b 100644
--- a/erpnext/stock/doctype/inventory_dimension/inventory_dimension.js
+++ b/erpnext/stock/doctype/inventory_dimension/inventory_dimension.js
@@ -35,14 +35,39 @@
refresh(frm) {
if (frm.doc.__onload && frm.doc.__onload.has_stock_ledger
&& frm.doc.__onload.has_stock_ledger.length) {
- let msg = __('Stock transactions exists against this dimension, user can not update document.');
- frm.dashboard.add_comment(msg, 'blue', true);
+ let allow_to_edit_fields = ['disabled', 'fetch_from_parent',
+ 'type_of_transaction', 'condition'];
frm.fields.forEach((field) => {
- if (field.df.fieldname !== 'disabled') {
+ if (!in_list(allow_to_edit_fields, field.df.fieldname)) {
frm.set_df_property(field.df.fieldname, "read_only", "1");
}
});
}
+
+ if (!frm.is_new()) {
+ frm.add_custom_button(__('Delete Dimension'), () => {
+ frm.trigger('delete_dimension');
+ });
+ }
+ },
+
+ delete_dimension(frm) {
+ let msg = (`
+ Custom fields related to this dimension will be deleted on deletion of dimension.
+ <br> Do you want to delete {0} dimension?
+ `);
+
+ frappe.confirm(__(msg, [frm.doc.name.bold()]), () => {
+ frappe.call({
+ method: 'erpnext.stock.doctype.inventory_dimension.inventory_dimension.delete_dimension',
+ args: {
+ dimension: frm.doc.name
+ },
+ callback: function() {
+ frappe.set_route('List', 'Inventory Dimension');
+ }
+ });
+ });
}
});
diff --git a/erpnext/stock/doctype/inventory_dimension/inventory_dimension.json b/erpnext/stock/doctype/inventory_dimension/inventory_dimension.json
index 8b334d1..03e7fda 100644
--- a/erpnext/stock/doctype/inventory_dimension/inventory_dimension.json
+++ b/erpnext/stock/doctype/inventory_dimension/inventory_dimension.json
@@ -1,6 +1,5 @@
{
"actions": [],
- "allow_rename": 1,
"autoname": "field:dimension_name",
"creation": "2022-06-17 13:04:16.554051",
"doctype": "DocType",
@@ -22,6 +21,7 @@
"document_type",
"istable",
"type_of_transaction",
+ "fetch_from_parent",
"column_break_16",
"condition",
"applicable_condition_example_section",
@@ -101,12 +101,14 @@
"fieldname": "target_fieldname",
"fieldtype": "Data",
"label": "Target Fieldname (Stock Ledger Entry)",
+ "no_copy": 1,
"read_only": 1
},
{
"fieldname": "source_fieldname",
"fieldtype": "Data",
"label": "Source Fieldname",
+ "no_copy": 1,
"read_only": 1
},
{
@@ -123,7 +125,7 @@
"fieldname": "type_of_transaction",
"fieldtype": "Select",
"label": "Type of Transaction",
- "options": "\nInward\nOutward"
+ "options": "\nInward\nOutward\nBoth"
},
{
"fieldname": "html_19",
@@ -140,11 +142,18 @@
{
"fieldname": "column_break_4",
"fieldtype": "Column Break"
+ },
+ {
+ "depends_on": "istable",
+ "description": "Set fieldname or DocType name like Supplier, Customer etc.",
+ "fieldname": "fetch_from_parent",
+ "fieldtype": "Data",
+ "label": "Fetch Value From Parent Form"
}
],
"index_web_pages_for_search": 1,
"links": [],
- "modified": "2022-07-19 21:06:11.824976",
+ "modified": "2022-08-17 11:43:24.722441",
"modified_by": "Administrator",
"module": "Stock",
"name": "Inventory Dimension",
diff --git a/erpnext/stock/doctype/inventory_dimension/inventory_dimension.py b/erpnext/stock/doctype/inventory_dimension/inventory_dimension.py
index 5a9541f..4ff8f33 100644
--- a/erpnext/stock/doctype/inventory_dimension/inventory_dimension.py
+++ b/erpnext/stock/doctype/inventory_dimension/inventory_dimension.py
@@ -43,13 +43,37 @@
return
old_doc = self._doc_before_save
+ allow_to_edit_fields = [
+ "disabled",
+ "fetch_from_parent",
+ "type_of_transaction",
+ "condition",
+ ]
+
for field in frappe.get_meta("Inventory Dimension").fields:
- if field.fieldname != "disabled" and old_doc.get(field.fieldname) != self.get(field.fieldname):
+ if field.fieldname not in allow_to_edit_fields and old_doc.get(field.fieldname) != self.get(
+ field.fieldname
+ ):
msg = f"""The user can not change value of the field {bold(field.label)} because
stock transactions exists against the dimension {bold(self.name)}."""
frappe.throw(_(msg), DoNotChangeError)
+ def on_trash(self):
+ self.delete_custom_fields()
+
+ def delete_custom_fields(self):
+ filters = {"fieldname": self.source_fieldname}
+
+ if self.document_type:
+ filters["dt"] = self.document_type
+
+ for field in frappe.get_all("Custom Field", filters=filters):
+ frappe.delete_doc("Custom Field", field.name)
+
+ msg = f"Deleted custom fields related to the dimension {self.name}"
+ frappe.msgprint(_(msg))
+
def reset_value(self):
if self.apply_to_all_doctypes:
self.istable = 0
@@ -76,30 +100,35 @@
self.add_custom_fields()
def add_custom_fields(self):
- dimension_field = dict(
- fieldname=self.source_fieldname,
- fieldtype="Link",
- insert_after="warehouse",
- options=self.reference_document,
- label=self.dimension_name,
- )
+ dimension_fields = [
+ dict(
+ fieldname="inventory_dimension",
+ fieldtype="Section Break",
+ insert_after="warehouse",
+ label="Inventory Dimension",
+ collapsible=1,
+ ),
+ dict(
+ fieldname=self.source_fieldname,
+ fieldtype="Link",
+ insert_after="inventory_dimension",
+ options=self.reference_document,
+ label=self.dimension_name,
+ ),
+ ]
custom_fields = {}
if self.apply_to_all_doctypes:
for doctype in get_inventory_documents():
- if not frappe.db.get_value(
- "Custom Field", {"dt": doctype[0], "fieldname": self.source_fieldname}
- ):
- custom_fields.setdefault(doctype[0], dimension_field)
- elif not frappe.db.get_value(
- "Custom Field", {"dt": self.document_type, "fieldname": self.source_fieldname}
- ):
- custom_fields.setdefault(self.document_type, dimension_field)
+ custom_fields.setdefault(doctype[0], dimension_fields)
+ else:
+ custom_fields.setdefault(self.document_type, dimension_fields)
if not frappe.db.get_value(
"Custom Field", {"dt": "Stock Ledger Entry", "fieldname": self.target_fieldname}
):
+ dimension_field = dimension_fields[1]
dimension_field["fieldname"] = self.target_fieldname
custom_fields["Stock Ledger Entry"] = dimension_field
@@ -143,7 +172,7 @@
elif (
row.type_of_transaction == "Outward"
if doc.docstatus == 1
- else row.type_of_transaction != "Inward"
+ else row.type_of_transaction != "Outward"
) and sl_dict.actual_qty > 0:
continue
@@ -166,7 +195,14 @@
if not frappe.local.document_wise_inventory_dimensions.get(doctype):
dimensions = frappe.get_all(
"Inventory Dimension",
- fields=["name", "source_fieldname", "condition", "target_fieldname", "type_of_transaction"],
+ fields=[
+ "name",
+ "source_fieldname",
+ "condition",
+ "target_fieldname",
+ "type_of_transaction",
+ "fetch_from_parent",
+ ],
filters={"disabled": 0},
or_filters={"document_type": doctype, "apply_to_all_doctypes": 1},
)
@@ -194,3 +230,9 @@
frappe.local.inventory_dimensions = dimensions
return frappe.local.inventory_dimensions
+
+
+@frappe.whitelist()
+def delete_dimension(dimension):
+ doc = frappe.get_doc("Inventory Dimension", dimension)
+ doc.delete()
diff --git a/erpnext/stock/doctype/inventory_dimension/test_inventory_dimension.py b/erpnext/stock/doctype/inventory_dimension/test_inventory_dimension.py
index 998a0e9..cc90b74 100644
--- a/erpnext/stock/doctype/inventory_dimension/test_inventory_dimension.py
+++ b/erpnext/stock/doctype/inventory_dimension/test_inventory_dimension.py
@@ -8,6 +8,7 @@
CanNotBeChildDoc,
CanNotBeDefaultDimension,
DoNotChangeError,
+ delete_dimension,
)
from erpnext.stock.doctype.stock_entry.stock_entry_utils import make_stock_entry
from erpnext.stock.doctype.warehouse.test_warehouse import create_warehouse
@@ -42,6 +43,32 @@
self.assertRaises(CanNotBeDefaultDimension, inv_dim1.insert)
+ def test_delete_inventory_dimension(self):
+ inv_dim1 = create_inventory_dimension(
+ reference_document="Shelf",
+ type_of_transaction="Outward",
+ dimension_name="From Shelf",
+ apply_to_all_doctypes=0,
+ document_type="Stock Entry Detail",
+ condition="parent.purpose == 'Material Issue'",
+ )
+
+ inv_dim1.save()
+
+ custom_field = frappe.db.get_value(
+ "Custom Field", {"fieldname": "from_shelf", "dt": "Stock Entry Detail"}, "name"
+ )
+
+ self.assertTrue(custom_field)
+
+ delete_dimension(inv_dim1.name)
+
+ custom_field = frappe.db.get_value(
+ "Custom Field", {"fieldname": "from_shelf", "dt": "Stock Entry Detail"}, "name"
+ )
+
+ self.assertFalse(custom_field)
+
def test_inventory_dimension(self):
warehouse = "Shelf Warehouse - _TC"
item_code = "_Test Item"