Merge pull request #27735 from GangaManoj/fix-so-cancellation-message
fix: Sales Order cancellation message
diff --git a/erpnext/maintenance/doctype/maintenance_visit/test_maintenance_visit.py b/erpnext/maintenance/doctype/maintenance_visit/test_maintenance_visit.py
index a0c1a33..6a9e70a 100644
--- a/erpnext/maintenance/doctype/maintenance_visit/test_maintenance_visit.py
+++ b/erpnext/maintenance/doctype/maintenance_visit/test_maintenance_visit.py
@@ -3,7 +3,39 @@
import unittest
+import frappe
+from frappe.utils.data import today
+
# test_records = frappe.get_test_records('Maintenance Visit')
class TestMaintenanceVisit(unittest.TestCase):
pass
+
+def make_maintenance_visit():
+ mv = frappe.new_doc("Maintenance Visit")
+ mv.company = "_Test Company"
+ mv.customer = "_Test Customer"
+ mv.mntc_date = today()
+ mv.completion_status = "Partially Completed"
+
+ sales_person = make_sales_person("Dwight Schrute")
+
+ mv.append("purposes", {
+ "item_code": "_Test Item",
+ "sales_person": "Sales Team",
+ "description": "Test Item",
+ "work_done": "Test Work Done",
+ "service_person": sales_person.name
+ })
+ mv.insert(ignore_permissions=True)
+
+ return mv
+
+def make_sales_person(name):
+ sales_person = frappe.get_doc({
+ 'doctype': "Sales Person",
+ 'sales_person_name': name
+ })
+ sales_person.insert(ignore_if_duplicate = True)
+
+ return sales_person
diff --git a/erpnext/selling/doctype/sales_order/sales_order.py b/erpnext/selling/doctype/sales_order/sales_order.py
index 8cb0f29..47b8ebd 100755
--- a/erpnext/selling/doctype/sales_order/sales_order.py
+++ b/erpnext/selling/doctype/sales_order/sales_order.py
@@ -223,60 +223,15 @@
check_credit_limit(self.customer, self.company)
def check_nextdoc_docstatus(self):
- # Checks Delivery Note
- submit_dn = frappe.db.sql_list("""
- select t1.name
- from `tabDelivery Note` t1,`tabDelivery Note Item` t2
- where t1.name = t2.parent and t2.against_sales_order = %s and t1.docstatus = 1""", self.name)
-
- if submit_dn:
- submit_dn = [get_link_to_form("Delivery Note", dn) for dn in submit_dn]
- frappe.throw(_("Delivery Notes {0} must be cancelled before cancelling this Sales Order")
- .format(", ".join(submit_dn)))
-
- # Checks Sales Invoice
- submit_rv = frappe.db.sql_list("""select t1.name
+ linked_invoices = frappe.db.sql_list("""select distinct t1.name
from `tabSales Invoice` t1,`tabSales Invoice Item` t2
- where t1.name = t2.parent and t2.sales_order = %s and t1.docstatus < 2""",
+ where t1.name = t2.parent and t2.sales_order = %s and t1.docstatus = 0""",
self.name)
- if submit_rv:
- submit_rv = [get_link_to_form("Sales Invoice", si) for si in submit_rv]
- frappe.throw(_("Sales Invoice {0} must be cancelled before cancelling this Sales Order")
- .format(", ".join(submit_rv)))
-
- #check maintenance schedule
- submit_ms = frappe.db.sql_list("""
- select t1.name
- from `tabMaintenance Schedule` t1, `tabMaintenance Schedule Item` t2
- where t2.parent=t1.name and t2.sales_order = %s and t1.docstatus = 1""", self.name)
-
- if submit_ms:
- submit_ms = [get_link_to_form("Maintenance Schedule", ms) for ms in submit_ms]
- frappe.throw(_("Maintenance Schedule {0} must be cancelled before cancelling this Sales Order")
- .format(", ".join(submit_ms)))
-
- # check maintenance visit
- submit_mv = frappe.db.sql_list("""
- select t1.name
- from `tabMaintenance Visit` t1, `tabMaintenance Visit Purpose` t2
- where t2.parent=t1.name and t2.prevdoc_docname = %s and t1.docstatus = 1""",self.name)
-
- if submit_mv:
- submit_mv = [get_link_to_form("Maintenance Visit", mv) for mv in submit_mv]
- frappe.throw(_("Maintenance Visit {0} must be cancelled before cancelling this Sales Order")
- .format(", ".join(submit_mv)))
-
- # check work order
- pro_order = frappe.db.sql_list("""
- select name
- from `tabWork Order`
- where sales_order = %s and docstatus = 1""", self.name)
-
- if pro_order:
- pro_order = [get_link_to_form("Work Order", po) for po in pro_order]
- frappe.throw(_("Work Order {0} must be cancelled before cancelling this Sales Order")
- .format(", ".join(pro_order)))
+ if linked_invoices:
+ linked_invoices = [get_link_to_form("Sales Invoice", si) for si in linked_invoices]
+ frappe.throw(_("Sales Invoice {0} must be deleted before cancelling this Sales Order")
+ .format(", ".join(linked_invoices)))
def check_modified_date(self):
mod_db = frappe.db.get_value("Sales Order", self.name, "modified")
diff --git a/erpnext/selling/doctype/sales_order/test_sales_order.py b/erpnext/selling/doctype/sales_order/test_sales_order.py
index 644c0ac..2a0752e 100644
--- a/erpnext/selling/doctype/sales_order/test_sales_order.py
+++ b/erpnext/selling/doctype/sales_order/test_sales_order.py
@@ -10,6 +10,12 @@
from frappe.utils import add_days, flt, getdate, nowdate
from erpnext.controllers.accounts_controller import update_child_qty_rate
+from erpnext.maintenance.doctype.maintenance_schedule.test_maintenance_schedule import (
+ make_maintenance_schedule,
+)
+from erpnext.maintenance.doctype.maintenance_visit.test_maintenance_visit import (
+ make_maintenance_visit,
+)
from erpnext.manufacturing.doctype.blanket_order.test_blanket_order import make_blanket_order
from erpnext.selling.doctype.product_bundle.test_product_bundle import make_product_bundle
from erpnext.selling.doctype.sales_order.sales_order import (
@@ -1278,6 +1284,72 @@
self.assertRaises(frappe.ValidationError, so.cancel)
+ def test_so_cancellation_after_si_submission(self):
+ """
+ Test to check if Sales Order gets cancelled when linked Sales Invoice has been Submitted
+ Expected result: Sales Order should not get cancelled
+ """
+ so = make_sales_order()
+ so.submit()
+ si = make_sales_invoice(so.name)
+ si.submit()
+
+ so.load_from_db()
+ self.assertRaises(frappe.LinkExistsError, so.cancel)
+
+ def test_so_cancellation_after_dn_submission(self):
+ """
+ Test to check if Sales Order gets cancelled when linked Delivery Note has been Submitted
+ Expected result: Sales Order should not get cancelled
+ """
+ so = make_sales_order()
+ so.submit()
+ dn = make_delivery_note(so.name)
+ dn.submit()
+
+ so.load_from_db()
+ self.assertRaises(frappe.LinkExistsError, so.cancel)
+
+ def test_so_cancellation_after_maintenance_schedule_submission(self):
+ """
+ Expected result: Sales Order should not get cancelled
+ """
+ so = make_sales_order()
+ so.submit()
+ ms = make_maintenance_schedule()
+ ms.items[0].sales_order = so.name
+ ms.submit()
+
+ so.load_from_db()
+ self.assertRaises(frappe.LinkExistsError, so.cancel)
+
+ def test_so_cancellation_after_maintenance_visit_submission(self):
+ """
+ Expected result: Sales Order should not get cancelled
+ """
+ so = make_sales_order()
+ so.submit()
+ mv = make_maintenance_visit()
+ mv.purposes[0].prevdoc_doctype = "Sales Order"
+ mv.purposes[0].prevdoc_docname = so.name
+ mv.submit()
+
+ so.load_from_db()
+ self.assertRaises(frappe.LinkExistsError, so.cancel)
+
+ def test_so_cancellation_after_work_order_submission(self):
+ """
+ Expected result: Sales Order should not get cancelled
+ """
+ from erpnext.manufacturing.doctype.work_order.test_work_order import make_wo_order_test_record
+
+ so = make_sales_order(item_code="_Test FG Item", qty=10)
+ so.submit()
+ make_wo_order_test_record(sales_order=so.name)
+
+ so.load_from_db()
+ self.assertRaises(frappe.LinkExistsError, so.cancel)
+
def test_payment_terms_are_fetched_when_creating_sales_invoice(self):
from erpnext.accounts.doctype.payment_entry.test_payment_entry import (
create_payment_terms_template,