fix: Duplicate items check in Sales Invoice (#18660)
* fix: Duplicate items check in sales Invoice
* fix: Commonified function for duplicate items check in selling controller
* fix: Set valuation rate and transaction date in child tabel
diff --git a/erpnext/controllers/selling_controller.py b/erpnext/controllers/selling_controller.py
index 2cbe596..52d58dc 100644
--- a/erpnext/controllers/selling_controller.py
+++ b/erpnext/controllers/selling_controller.py
@@ -45,6 +45,7 @@
self.set_gross_profit()
set_default_income_account_for_item(self)
self.set_customer_address()
+ self.validate_for_duplicate_items()
def set_missing_values(self, for_validate=False):
@@ -381,6 +382,34 @@
if self.get(address_field):
self.set(address_display_field, get_address_display(self.get(address_field)))
+ def validate_for_duplicate_items(self):
+ check_list, chk_dupl_itm = [], []
+ if cint(frappe.db.get_single_value("Selling Settings", "allow_multiple_items")):
+ return
+
+ for d in self.get('items'):
+ if self.doctype == "Sales Invoice":
+ e = [d.item_code, d.description, d.warehouse, d.sales_order or d.delivery_note, d.batch_no or '']
+ f = [d.item_code, d.description, d.sales_order or d.delivery_note]
+ elif self.doctype == "Delivery Note":
+ e = [d.item_code, d.description, d.warehouse, d.against_sales_order or d.against_sales_invoice, d.batch_no or '']
+ f = [d.item_code, d.description, d.against_sales_order or d.against_sales_invoice]
+ elif self.doctype == "Sales Order":
+ e = [d.item_code, d.description, d.warehouse, d.batch_no or '']
+ f = [d.item_code, d.description]
+
+ if frappe.db.get_value("Item", d.item_code, "is_stock_item") == 1:
+ if e in check_list:
+ frappe.throw(_("Note: Item {0} entered multiple times").format(d.item_code))
+ else:
+ check_list.append(e)
+ else:
+ if f in chk_dupl_itm:
+ frappe.throw(_("Note: Item {0} entered multiple times").format(d.item_code))
+ else:
+ chk_dupl_itm.append(f)
+
+
def validate_items(self):
# validate items to see if they have is_sales_item enabled
from erpnext.controllers.buying_controller import validate_item_type
diff --git a/erpnext/selling/doctype/sales_order/sales_order.py b/erpnext/selling/doctype/sales_order/sales_order.py
index 09dc9a9..4342af5 100755
--- a/erpnext/selling/doctype/sales_order/sales_order.py
+++ b/erpnext/selling/doctype/sales_order/sales_order.py
@@ -72,9 +72,7 @@
frappe.msgprint(_("Warning: Sales Order {0} already exists against Customer's Purchase Order {1}").format(so[0][0], self.po_no))
def validate_for_items(self):
- check_list = []
for d in self.get('items'):
- check_list.append(cstr(d.item_code))
# used for production plan
d.transaction_date = self.transaction_date
@@ -83,13 +81,6 @@
where item_code = %s and warehouse = %s", (d.item_code, d.warehouse))
d.projected_qty = tot_avail_qty and flt(tot_avail_qty[0][0]) or 0
- # check for same entry multiple times
- unique_chk_list = set(check_list)
- if len(unique_chk_list) != len(check_list) and \
- not cint(frappe.db.get_single_value("Selling Settings", "allow_multiple_items")):
- frappe.msgprint(_("Same item has been entered multiple times"),
- title=_("Warning"), indicator='orange')
-
def product_bundle_has_stock_item(self, product_bundle):
"""Returns true if product bundle has stock item"""
ret = len(frappe.db.sql("""select i.name from tabItem i, `tabProduct Bundle Item` pbi
diff --git a/erpnext/stock/doctype/delivery_note/delivery_note.py b/erpnext/stock/doctype/delivery_note/delivery_note.py
index 2de9b97..f79d127 100644
--- a/erpnext/stock/doctype/delivery_note/delivery_note.py
+++ b/erpnext/stock/doctype/delivery_note/delivery_note.py
@@ -166,24 +166,7 @@
frappe.throw(_("Customer {0} does not belong to project {1}").format(self.customer, self.project))
def validate_for_items(self):
- check_list, chk_dupl_itm = [], []
- if cint(frappe.db.get_single_value("Selling Settings", "allow_multiple_items")):
- return
-
for d in self.get('items'):
- e = [d.item_code, d.description, d.warehouse, d.against_sales_order or d.against_sales_invoice, d.batch_no or '']
- f = [d.item_code, d.description, d.against_sales_order or d.against_sales_invoice]
-
- if frappe.db.get_value("Item", d.item_code, "is_stock_item") == 1:
- if e in check_list:
- frappe.msgprint(_("Note: Item {0} entered multiple times").format(d.item_code))
- else:
- check_list.append(e)
- else:
- if f in chk_dupl_itm:
- frappe.msgprint(_("Note: Item {0} entered multiple times").format(d.item_code))
- else:
- chk_dupl_itm.append(f)
#Customer Provided parts will have zero valuation rate
if frappe.db.get_value('Item', d.item_code, 'is_customer_provided_item'):
d.allow_zero_valuation_rate = 1