refactor: validate_serial_numbers
diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py
index e1ad2ab..a57a9f4 100644
--- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py
+++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py
@@ -39,7 +39,6 @@
from erpnext.projects.doctype.timesheet.timesheet import get_projectwise_timesheet_data
from erpnext.setup.doctype.company.company import update_company_current_month_sales
from erpnext.stock.doctype.delivery_note.delivery_note import update_billed_amount_based_on_so
-from erpnext.stock.doctype.serial_no.serial_no import get_delivery_note_serial_no, get_serial_nos
form_grid_templates = {"items": "templates/form_grid/item_grid.html"}
@@ -1642,48 +1641,9 @@
"""
validate serial number agains Delivery Note and Sales Invoice
"""
- self.set_serial_no_against_delivery_note()
- self.validate_serial_against_delivery_note()
-
- def set_serial_no_against_delivery_note(self):
for item in self.items:
- if item.serial_no and item.delivery_note and item.qty != len(get_serial_nos(item.serial_no)):
- item.serial_no = get_delivery_note_serial_no(item.item_code, item.qty, item.delivery_note)
-
- def validate_serial_against_delivery_note(self):
- """
- validate if the serial numbers in Sales Invoice Items are same as in
- Delivery Note Item
- """
-
- for item in self.items:
- if not item.delivery_note or not item.dn_detail:
- continue
-
- serial_nos = frappe.db.get_value("Delivery Note Item", item.dn_detail, "serial_no") or ""
- dn_serial_nos = set(get_serial_nos(serial_nos))
-
- serial_nos = item.serial_no or ""
- si_serial_nos = set(get_serial_nos(serial_nos))
- serial_no_diff = si_serial_nos - dn_serial_nos
-
- if serial_no_diff:
- dn_link = frappe.utils.get_link_to_form("Delivery Note", item.delivery_note)
- serial_no_msg = ", ".join(frappe.bold(d) for d in serial_no_diff)
-
- msg = _("Row #{0}: The following Serial Nos are not present in Delivery Note {1}:").format(
- item.idx, dn_link
- )
- msg += " " + serial_no_msg
-
- frappe.throw(msg=msg, title=_("Serial Nos Mismatch"))
-
- if item.serial_no and cint(item.qty) != len(si_serial_nos):
- frappe.throw(
- _("Row #{0}: {1} Serial numbers required for Item {2}. You have provided {3}.").format(
- item.idx, item.qty, item.item_code, len(si_serial_nos)
- )
- )
+ item.set_serial_no_against_delivery_note()
+ item.validate_serial_against_delivery_note()
def update_project(self):
if self.project:
diff --git a/erpnext/accounts/doctype/sales_invoice_item/sales_invoice_item.py b/erpnext/accounts/doctype/sales_invoice_item/sales_invoice_item.py
index cf18529..cd235bf 100644
--- a/erpnext/accounts/doctype/sales_invoice_item/sales_invoice_item.py
+++ b/erpnext/accounts/doctype/sales_invoice_item/sales_invoice_item.py
@@ -5,8 +5,10 @@
import frappe
from frappe import _
from frappe.model.document import Document
+from frappe.utils.data import cint
from erpnext.assets.doctype.asset.depreciation import get_disposal_account_and_cost_center
+from erpnext.stock.doctype.serial_no.serial_no import get_delivery_note_serial_no, get_serial_nos
class SalesInvoiceItem(Document):
@@ -124,3 +126,39 @@
self.income_account = disposal_account
if not self.cost_center:
self.cost_center = depreciation_cost_center
+
+ def set_serial_no_against_delivery_note(self):
+ """Set serial no based on delivery note."""
+ if self.serial_no and self.delivery_note and self.qty != len(get_serial_nos(self.serial_no)):
+ self.serial_no = get_delivery_note_serial_no(self.item_code, self.qty, self.delivery_note)
+
+ def validate_serial_against_delivery_note(self):
+ """Ensure the serial numbers in this Sales Invoice Item are same as in the linked Delivery Note."""
+ if not self.delivery_note or not self.dn_detail:
+ return
+
+ serial_nos = frappe.db.get_value("Delivery Note Item", self.dn_detail, "serial_no") or ""
+ dn_serial_nos = set(get_serial_nos(serial_nos))
+
+ serial_nos = self.serial_no or ""
+ si_serial_nos = set(get_serial_nos(serial_nos))
+ serial_no_diff = si_serial_nos - dn_serial_nos
+
+ if serial_no_diff:
+ dn_link = frappe.utils.get_link_to_form("Delivery Note", self.delivery_note)
+ msg = (
+ _("Row #{0}: The following serial numbers are not present in Delivery Note {1}:").format(
+ self.idx, dn_link
+ )
+ + " "
+ + ", ".join(frappe.bold(d) for d in serial_no_diff)
+ )
+
+ frappe.throw(msg=msg, title=_("Serial Nos Mismatch"))
+
+ if self.serial_no and cint(self.qty) != len(si_serial_nos):
+ frappe.throw(
+ _(
+ "Row #{0}: {1} serial numbers are required for Item {2}. You have provided {3} serial numbers."
+ ).format(self.idx, self.qty, self.item_code, len(si_serial_nos))
+ )