fix: Validation for invalid serial nos at POS invoice level (#29447)
diff --git a/erpnext/accounts/doctype/pos_invoice/pos_invoice.py b/erpnext/accounts/doctype/pos_invoice/pos_invoice.py
index 134bccf..f66abdc 100644
--- a/erpnext/accounts/doctype/pos_invoice/pos_invoice.py
+++ b/erpnext/accounts/doctype/pos_invoice/pos_invoice.py
@@ -158,6 +158,20 @@
frappe.throw(_("Row #{}: Serial No. {} has already been transacted into another Sales Invoice. Please select valid serial no.")
.format(item.idx, bold_delivered_serial_nos), title=_("Item Unavailable"))
+ def validate_invalid_serial_nos(self, item):
+ serial_nos = get_serial_nos(item.serial_no)
+ error_msg = []
+ invalid_serials, msg = "", ""
+ for serial_no in serial_nos:
+ if not frappe.db.exists('Serial No', serial_no):
+ invalid_serials = invalid_serials + (", " if invalid_serials else "") + serial_no
+ msg = (_("Row #{}: Following Serial numbers for item {} are <b>Invalid</b>: {}").format(item.idx, frappe.bold(item.get("item_code")), frappe.bold(invalid_serials)))
+ if invalid_serials:
+ error_msg.append(msg)
+
+ if error_msg:
+ frappe.throw(error_msg, title=_("Invalid Item"), as_list=True)
+
def validate_stock_availablility(self):
if self.is_return or self.docstatus != 1:
return
@@ -167,6 +181,7 @@
if d.serial_no:
self.validate_pos_reserved_serial_nos(d)
self.validate_delivered_serial_nos(d)
+ self.validate_invalid_serial_nos(d)
elif d.batch_no:
self.validate_pos_reserved_batch_qty(d)
else:
diff --git a/erpnext/accounts/doctype/pos_invoice/test_pos_invoice.py b/erpnext/accounts/doctype/pos_invoice/test_pos_invoice.py
index 56479a0..ba751c0 100644
--- a/erpnext/accounts/doctype/pos_invoice/test_pos_invoice.py
+++ b/erpnext/accounts/doctype/pos_invoice/test_pos_invoice.py
@@ -354,6 +354,24 @@
pos2.insert()
self.assertRaises(frappe.ValidationError, pos2.submit)
+ def test_invalid_serial_no_validation(self):
+ from erpnext.stock.doctype.stock_entry.test_stock_entry import make_serialized_item
+
+ se = make_serialized_item(company='_Test Company',
+ target_warehouse="Stores - _TC", cost_center='Main - _TC', expense_account='Cost of Goods Sold - _TC')
+ serial_nos = se.get("items")[0].serial_no + 'wrong'
+
+ pos = create_pos_invoice(company='_Test Company', debit_to='Debtors - _TC',
+ account_for_change_amount='Cash - _TC', warehouse='Stores - _TC', income_account='Sales - _TC',
+ expense_account='Cost of Goods Sold - _TC', cost_center='Main - _TC',
+ item=se.get("items")[0].item_code, rate=1000, qty=2, do_not_save=1)
+
+ pos.get('items')[0].has_serial_no = 1
+ pos.get('items')[0].serial_no = serial_nos
+ pos.insert()
+
+ self.assertRaises(frappe.ValidationError, pos.submit)
+
def test_loyalty_points(self):
from erpnext.accounts.doctype.loyalty_program.loyalty_program import (
get_loyalty_program_details_with_points,