mirror of
https://github.com/frappe/erpnext.git
synced 2026-05-03 21:48:27 +00:00
Merge pull request #40490 from frappe/mergify/bp/version-15-hotfix/pr-40485
refactor: validate SO and SI references in Delivery Notes (backport #40485)
This commit is contained in:
@@ -2156,13 +2156,14 @@ def make_sales_order(**args):
|
|||||||
return so
|
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)
|
frappe.db.set_single_value("Stock Settings", "allow_negative_stock", 1)
|
||||||
|
|
||||||
dn = make_delivery_note(so)
|
dn = make_delivery_note(so)
|
||||||
dn.get("items")[0].qty = delivered_qty or 5
|
dn.get("items")[0].qty = delivered_qty or 5
|
||||||
dn.insert()
|
dn.insert()
|
||||||
dn.submit()
|
if not do_not_submit:
|
||||||
|
dn.submit()
|
||||||
return dn
|
return dn
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -251,6 +251,7 @@ class DeliveryNote(SellingController):
|
|||||||
def validate(self):
|
def validate(self):
|
||||||
self.validate_posting_time()
|
self.validate_posting_time()
|
||||||
super(DeliveryNote, self).validate()
|
super(DeliveryNote, self).validate()
|
||||||
|
self.validate_references()
|
||||||
self.set_status()
|
self.set_status()
|
||||||
self.so_required()
|
self.so_required()
|
||||||
self.validate_proj_cust()
|
self.validate_proj_cust()
|
||||||
@@ -341,6 +342,58 @@ class DeliveryNote(SellingController):
|
|||||||
|
|
||||||
item.serial_and_batch_bundle = cls_obj.serial_and_batch_bundle
|
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):
|
def validate_proj_cust(self):
|
||||||
"""check for does customer belong to same project as entered.."""
|
"""check for does customer belong to same project as entered.."""
|
||||||
if self.project and self.customer:
|
if self.project and self.customer:
|
||||||
|
|||||||
@@ -813,6 +813,15 @@ class TestDeliveryNote(FrappeTestCase):
|
|||||||
dn.cancel()
|
dn.cancel()
|
||||||
self.assertEqual(dn.status, "Cancelled")
|
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):
|
def test_dn_billing_status_case1(self):
|
||||||
# SO -> DN -> SI
|
# SO -> DN -> SI
|
||||||
so = make_sales_order(po_no="12345")
|
so = make_sales_order(po_no="12345")
|
||||||
|
|||||||
Reference in New Issue
Block a user