Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor: validate SO and SI references in Delivery Notes (backport #40485) #40490

Merged
merged 2 commits into from
Mar 16, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions erpnext/selling/doctype/sales_order/test_sales_order.py
Original file line number Diff line number Diff line change
Expand Up @@ -2156,13 +2156,14 @@ def make_sales_order(**args):
return so


def create_dn_against_so(so, delivered_qty=0):
def create_dn_against_so(so, delivered_qty=0, do_not_submit=False):
frappe.db.set_single_value("Stock Settings", "allow_negative_stock", 1)

dn = make_delivery_note(so)
dn.get("items")[0].qty = delivered_qty or 5
dn.insert()
dn.submit()
if not do_not_submit:
dn.submit()
return dn


Expand Down
53 changes: 53 additions & 0 deletions erpnext/stock/doctype/delivery_note/delivery_note.py
Original file line number Diff line number Diff line change
Expand Up @@ -251,6 +251,7 @@ def so_required(self):
def validate(self):
self.validate_posting_time()
super(DeliveryNote, self).validate()
self.validate_references()
self.set_status()
self.so_required()
self.validate_proj_cust()
Expand Down Expand Up @@ -341,6 +342,58 @@ def set_serial_and_batch_bundle_from_pick_list(self):

item.serial_and_batch_bundle = cls_obj.serial_and_batch_bundle

def validate_references(self):
self.validate_sales_order_references()
self.validate_sales_invoice_references()

def validate_sales_order_references(self):
err_msg = ""
for item in self.items:
if (item.against_sales_order and not item.so_detail) or (
not item.against_sales_order and item.so_detail
):
if not item.against_sales_order:
err_msg += (
_("'Sales Order' reference ({1}) is missing in row {0}").format(
frappe.bold(item.idx), frappe.bold("against_sales_order")
)
+ "<br>"
)
else:
err_msg += (
_("'Sales Order Item' reference ({1}) is missing in row {0}").format(
frappe.bold(item.idx), frappe.bold("so_detail")
)
+ "<br>"
)

if err_msg:
frappe.throw(err_msg, title=_("References to Sales Orders are Incomplete"))

def validate_sales_invoice_references(self):
err_msg = ""
for item in self.items:
if (item.against_sales_invoice and not item.si_detail) or (
not item.against_sales_invoice and item.si_detail
):
if not item.against_sales_invoice:
err_msg += (
_("'Sales Invoice' reference ({1}) is missing in row {0}").format(
frappe.bold(item.idx), frappe.bold("against_sales_invoice")
)
+ "<br>"
)
else:
err_msg += (
_("'Sales Invoice Item' reference ({1}) is missing in row {0}").format(
frappe.bold(item.idx), frappe.bold("si_detail")
)
+ "<br>"
)

if err_msg:
frappe.throw(err_msg, title=_("References to Sales Invoices are Incomplete"))

def validate_proj_cust(self):
"""check for does customer belong to same project as entered.."""
if self.project and self.customer:
Expand Down
9 changes: 9 additions & 0 deletions erpnext/stock/doctype/delivery_note/test_delivery_note.py
Original file line number Diff line number Diff line change
Expand Up @@ -813,6 +813,15 @@ def test_closed_delivery_note(self):
dn.cancel()
self.assertEqual(dn.status, "Cancelled")

def test_sales_order_reference_validation(self):
so = make_sales_order(po_no="12345")
dn = create_dn_against_so(so.name, delivered_qty=2, do_not_submit=True)
dn.items[0].against_sales_order = None
self.assertRaises(frappe.ValidationError, dn.save)
dn.reload()
dn.items[0].so_detail = None
self.assertRaises(frappe.ValidationError, dn.save)

def test_dn_billing_status_case1(self):
# SO -> DN -> SI
so = make_sales_order(po_no="12345")
Expand Down
Loading