feat: allow to edit Stock Quantity in the Sales and Purchase Transactions (#36600)
feat: allow to edit Stock Quantity in the Sales and Purchase transactions
diff --git a/erpnext/controllers/buying_controller.py b/erpnext/controllers/buying_controller.py
index c302ece..a76abe2 100644
--- a/erpnext/controllers/buying_controller.py
+++ b/erpnext/controllers/buying_controller.py
@@ -418,6 +418,10 @@
item.bom = None
def set_qty_as_per_stock_uom(self):
+ allow_to_edit_stock_qty = frappe.db.get_single_value(
+ "Stock Settings", "allow_to_edit_stock_uom_qty_for_purchase"
+ )
+
for d in self.get("items"):
if d.meta.get_field("stock_qty"):
# Check if item code is present
@@ -432,6 +436,11 @@
d.conversion_factor, d.precision("conversion_factor")
)
+ if allow_to_edit_stock_qty:
+ d.stock_qty = flt(d.stock_qty, d.precision("stock_qty"))
+ if d.get("received_stock_qty"):
+ d.received_stock_qty = flt(d.received_stock_qty, d.precision("received_stock_qty"))
+
def validate_purchase_return(self):
for d in self.get("items"):
if self.is_return and flt(d.rejected_qty) != 0:
diff --git a/erpnext/controllers/selling_controller.py b/erpnext/controllers/selling_controller.py
index 9771f60..9014662 100644
--- a/erpnext/controllers/selling_controller.py
+++ b/erpnext/controllers/selling_controller.py
@@ -194,11 +194,17 @@
frappe.throw(_("Maximum discount for Item {0} is {1}%").format(d.item_code, discount))
def set_qty_as_per_stock_uom(self):
+ allow_to_edit_stock_qty = frappe.db.get_single_value(
+ "Stock Settings", "allow_to_edit_stock_uom_qty_for_sales"
+ )
+
for d in self.get("items"):
if d.meta.get_field("stock_qty"):
if not d.conversion_factor:
frappe.throw(_("Row {0}: Conversion Factor is mandatory").format(d.idx))
d.stock_qty = flt(d.qty) * flt(d.conversion_factor)
+ if allow_to_edit_stock_qty:
+ d.stock_qty = flt(d.stock_qty, d.precision("stock_qty"))
def validate_selling_price(self):
def throw_message(idx, item_name, rate, ref_rate_field):
diff --git a/erpnext/public/js/controllers/buying.js b/erpnext/public/js/controllers/buying.js
index 54f0aad..0860d9c 100644
--- a/erpnext/public/js/controllers/buying.js
+++ b/erpnext/public/js/controllers/buying.js
@@ -9,6 +9,7 @@
erpnext.buying.BuyingController = class BuyingController extends erpnext.TransactionController {
setup() {
super.setup();
+ this.toggle_enable_for_stock_uom("allow_to_edit_stock_uom_qty_for_purchase");
this.frm.email_field = "contact_email";
}
diff --git a/erpnext/public/js/controllers/transaction.js b/erpnext/public/js/controllers/transaction.js
index 975adc2..b0a9e40 100644
--- a/erpnext/public/js/controllers/transaction.js
+++ b/erpnext/public/js/controllers/transaction.js
@@ -224,6 +224,14 @@
}
}
+
+ toggle_enable_for_stock_uom(field) {
+ frappe.db.get_single_value('Stock Settings', field)
+ .then(value => {
+ this.frm.fields_dict["items"].grid.toggle_enable("stock_qty", value);
+ });
+ }
+
onload() {
var me = this;
@@ -1191,6 +1199,16 @@
]);
}
+ stock_qty(doc, cdt, cdn) {
+ let item = frappe.get_doc(cdt, cdn);
+ item.conversion_factor = 1.0;
+ if (item.stock_qty) {
+ item.conversion_factor = flt(item.stock_qty) / flt(item.qty);
+ }
+
+ refresh_field("conversion_factor", item.name, item.parentfield);
+ }
+
calculate_stock_uom_rate(doc, cdt, cdn) {
let item = frappe.get_doc(cdt, cdn);
item.stock_uom_rate = flt(item.rate)/flt(item.conversion_factor);
diff --git a/erpnext/public/js/utils/sales_common.js b/erpnext/public/js/utils/sales_common.js
index 89dcaa6..1d6daa5 100644
--- a/erpnext/public/js/utils/sales_common.js
+++ b/erpnext/public/js/utils/sales_common.js
@@ -8,6 +8,7 @@
erpnext.selling.SellingController = class SellingController extends erpnext.TransactionController {
setup() {
super.setup();
+ this.toggle_enable_for_stock_uom("allow_to_edit_stock_uom_qty_for_sales");
this.frm.email_field = "contact_email";
}
diff --git a/erpnext/stock/doctype/purchase_receipt_item/purchase_receipt_item.json b/erpnext/stock/doctype/purchase_receipt_item/purchase_receipt_item.json
index d31fec5..5eb3656 100644
--- a/erpnext/stock/doctype/purchase_receipt_item/purchase_receipt_item.json
+++ b/erpnext/stock/doctype/purchase_receipt_item/purchase_receipt_item.json
@@ -34,8 +34,8 @@
"sample_quantity",
"tracking_section",
"received_stock_qty",
- "stock_qty",
"col_break_tracking_section",
+ "stock_qty",
"returned_qty",
"rate_and_amount",
"price_list_rate",
@@ -858,7 +858,8 @@
},
{
"fieldname": "tracking_section",
- "fieldtype": "Section Break"
+ "fieldtype": "Section Break",
+ "label": "Qty as Per Stock UOM"
},
{
"fieldname": "col_break_tracking_section",
@@ -1060,7 +1061,7 @@
"idx": 1,
"istable": 1,
"links": [],
- "modified": "2023-07-26 12:55:15.234477",
+ "modified": "2023-08-11 16:16:16.504549",
"modified_by": "Administrator",
"module": "Stock",
"name": "Purchase Receipt Item",
diff --git a/erpnext/stock/doctype/stock_settings/stock_settings.json b/erpnext/stock/doctype/stock_settings/stock_settings.json
index 88b5575..4fbc0eb 100644
--- a/erpnext/stock/doctype/stock_settings/stock_settings.json
+++ b/erpnext/stock/doctype/stock_settings/stock_settings.json
@@ -18,6 +18,10 @@
"auto_insert_price_list_rate_if_missing",
"column_break_12",
"update_existing_price_list_rate",
+ "conversion_factor_section",
+ "allow_to_edit_stock_uom_qty_for_sales",
+ "column_break_lznj",
+ "allow_to_edit_stock_uom_qty_for_purchase",
"stock_validations_tab",
"section_break_9",
"over_delivery_receipt_allowance",
@@ -358,10 +362,6 @@
"label": "Allow Partial Reservation"
},
{
- "fieldname": "section_break_plhx",
- "fieldtype": "Section Break"
- },
- {
"fieldname": "column_break_mhzc",
"fieldtype": "Column Break"
},
@@ -400,6 +400,27 @@
"fieldname": "auto_reserve_stock_for_sales_order",
"fieldtype": "Check",
"label": "Auto Reserve Stock for Sales Order"
+ },
+ {
+ "fieldname": "conversion_factor_section",
+ "fieldtype": "Section Break",
+ "label": "Stock UOM Quantity"
+ },
+ {
+ "fieldname": "column_break_lznj",
+ "fieldtype": "Column Break"
+ },
+ {
+ "default": "0",
+ "fieldname": "allow_to_edit_stock_uom_qty_for_sales",
+ "fieldtype": "Check",
+ "label": "Allow to Edit Stock UOM Qty for Sales Documents"
+ },
+ {
+ "default": "0",
+ "fieldname": "allow_to_edit_stock_uom_qty_for_purchase",
+ "fieldtype": "Check",
+ "label": "Allow to Edit Stock UOM Qty for Purchase Documents"
}
],
"icon": "icon-cog",
diff --git a/erpnext/stock/doctype/stock_settings/stock_settings.py b/erpnext/stock/doctype/stock_settings/stock_settings.py
index 9ad3c9d..c7afb10 100644
--- a/erpnext/stock/doctype/stock_settings/stock_settings.py
+++ b/erpnext/stock/doctype/stock_settings/stock_settings.py
@@ -56,6 +56,8 @@
self.validate_clean_description_html()
self.validate_pending_reposts()
self.validate_stock_reservation()
+ self.change_precision_for_for_sales()
+ self.change_precision_for_purchase()
def validate_warehouses(self):
warehouse_fields = ["default_warehouse", "sample_retention_warehouse"]
@@ -167,6 +169,56 @@
def on_update(self):
self.toggle_warehouse_field_for_inter_warehouse_transfer()
+ def change_precision_for_for_sales(self):
+ doc_before_save = self.get_doc_before_save()
+ if doc_before_save and (
+ doc_before_save.allow_to_edit_stock_uom_qty_for_sales
+ == self.allow_to_edit_stock_uom_qty_for_sales
+ ):
+ return
+
+ if self.allow_to_edit_stock_uom_qty_for_sales:
+ doctypes = ["Sales Order Item", "Sales Invoice Item", "Delivery Note Item", "Quotation Item"]
+ self.make_property_setter_for_precision(doctypes)
+
+ def change_precision_for_purchase(self):
+ doc_before_save = self.get_doc_before_save()
+ if doc_before_save and (
+ doc_before_save.allow_to_edit_stock_uom_qty_for_purchase
+ == self.allow_to_edit_stock_uom_qty_for_purchase
+ ):
+ return
+
+ if self.allow_to_edit_stock_uom_qty_for_purchase:
+ doctypes = [
+ "Purchase Order Item",
+ "Purchase Receipt Item",
+ "Purchase Invoice Item",
+ "Request for Quotation Item",
+ "Supplier Quotation Item",
+ "Material Request Item",
+ ]
+ self.make_property_setter_for_precision(doctypes)
+
+ @staticmethod
+ def make_property_setter_for_precision(doctypes):
+ for doctype in doctypes:
+ if property_name := frappe.db.exists(
+ "Property Setter",
+ {"doc_type": doctype, "field_name": "conversion_factor", "property": "precision"},
+ ):
+ frappe.db.set_value("Property Setter", property_name, "value", 9)
+ continue
+
+ make_property_setter(
+ doctype,
+ "conversion_factor",
+ "precision",
+ 9,
+ "Float",
+ validate_fields_for_doctype=False,
+ )
+
def toggle_warehouse_field_for_inter_warehouse_transfer(self):
make_property_setter(
"Sales Invoice Item",