diff --git a/erpnext/selling/doctype/sales_order/sales_order.py b/erpnext/selling/doctype/sales_order/sales_order.py index 339fda80a3366612753df87ee88602121c153d11..f746aaf929cd246b68b35b2da1ab0f5f051ffdb7 100755 --- a/erpnext/selling/doctype/sales_order/sales_order.py +++ b/erpnext/selling/doctype/sales_order/sales_order.py @@ -526,6 +526,10 @@ class SalesOrder(SellingController): def update_status(self, status): self.check_modified_date() self.set_status(update=True, status=status) + # Upon Sales Order Re-open, check for credit limit. + # Limit should be checked after the 'Hold/Closed' status is reset. + if status == "Draft" and self.docstatus == 1: + self.check_credit_limit() self.update_reserved_qty() self.notify_update() clear_doctype_notifications(self) diff --git a/erpnext/selling/doctype/sales_order/test_sales_order.py b/erpnext/selling/doctype/sales_order/test_sales_order.py index 952ddc0e675bb6b3e95a835436995a90eff155c2..b47787fa7c7c88b1a7a6ebf8e61ae2e454335092 100644 --- a/erpnext/selling/doctype/sales_order/test_sales_order.py +++ b/erpnext/selling/doctype/sales_order/test_sales_order.py @@ -10,6 +10,7 @@ from frappe.core.doctype.user_permission.test_user_permission import create_user from frappe.tests.utils import FrappeTestCase, change_settings from frappe.utils import add_days, flt, getdate, nowdate, today +from erpnext.accounts.test.accounts_mixin import AccountsTestMixin from erpnext.controllers.accounts_controller import InvalidQtyError, update_child_qty_rate from erpnext.maintenance.doctype.maintenance_schedule.test_maintenance_schedule import ( make_maintenance_schedule, @@ -32,7 +33,7 @@ from erpnext.stock.doctype.item.test_item import make_item from erpnext.stock.doctype.stock_entry.stock_entry_utils import make_stock_entry -class TestSalesOrder(FrappeTestCase): +class TestSalesOrder(AccountsTestMixin, FrappeTestCase): @classmethod def setUpClass(cls): super().setUpClass() @@ -53,6 +54,9 @@ class TestSalesOrder(FrappeTestCase): frappe.conf.mute_notifications = 0 super().tearDownClass() + def setUp(self): + self.create_customer("_Test Customer Credit") + def tearDown(self): frappe.set_user("Administrator") @@ -2176,6 +2180,28 @@ class TestSalesOrder(FrappeTestCase): frappe.db.set_single_value("Stock Settings", "update_existing_price_list_rate", 0) frappe.db.set_single_value("Stock Settings", "auto_insert_price_list_rate_if_missing", 0) + def test_credit_limit_on_so_reopning(self): + # set credit limit + company = "_Test Company" + customer = frappe.get_doc("Customer", self.customer) + customer.credit_limits = [] + customer.append( + "credit_limits", {"company": company, "credit_limit": 1000, "bypass_credit_limit_check": False} + ) + customer.save() + + so1 = make_sales_order(qty=9, rate=100, do_not_submit=True) + so1.customer = self.customer + so1.save().submit() + + so1.update_status("Closed") + + so2 = make_sales_order(qty=9, rate=100, do_not_submit=True) + so2.customer = self.customer + so2.save().submit() + + self.assertRaises(frappe.ValidationError, so1.update_status, "Draft") + def automatically_fetch_payment_terms(enable=1): accounts_settings = frappe.get_doc("Accounts Settings")