From e05656963aeebe240e908c72c93a04b12c4a1bc3 Mon Sep 17 00:00:00 2001 From: shreyas Date: Wed, 19 Oct 2016 15:59:21 +0530 Subject: [PATCH 1/4] [Minor] Do not allow change in credit limit --- erpnext/selling/doctype/customer/customer.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/erpnext/selling/doctype/customer/customer.py b/erpnext/selling/doctype/customer/customer.py index e29169604e..18bd4432bd 100644 --- a/erpnext/selling/doctype/customer/customer.py +++ b/erpnext/selling/doctype/customer/customer.py @@ -69,6 +69,7 @@ class Customer(TransactionBase): self.flags.old_lead = self.lead_name validate_party_accounts(self) self.status = get_party_status(self) + self.validate_credit_limit_on_change() def on_update(self): self.validate_name_with_customer_group() @@ -125,6 +126,15 @@ class Customer(TransactionBase): if frappe.db.exists("Customer Group", self.name): frappe.throw(_("A Customer Group exists with same name please change the Customer name or rename the Customer Group"), frappe.NameError) + def validate_credit_limit_on_change(self): + customer = frappe.get_doc('Customer', self.name) + companies = [c.name for c in frappe.get_all("Company")] + + for company in companies: + outstanding_amt = get_customer_outstanding(customer.name, company) + if flt(self.credit_limit) < outstanding_amt: + frappe.throw(_("New credit limit is less than current outstanding amount for the customer. Credit limit has to be atleast {0}").format(outstanding_amt)) + def delete_customer_address(self): addresses = frappe.db.sql("""select name, lead from `tabAddress` where customer=%s""", (self.name,)) From 17f43da2a6a95304e95a9b51890dd9a55a295573 Mon Sep 17 00:00:00 2001 From: shreyas Date: Thu, 20 Oct 2016 15:56:18 +0530 Subject: [PATCH 2/4] [Test] Added test cases to evaluate customer credit limit --- erpnext/selling/doctype/customer/customer.py | 10 ++-- .../selling/doctype/customer/test_customer.py | 48 ++++++++++++++++++- 2 files changed, 52 insertions(+), 6 deletions(-) diff --git a/erpnext/selling/doctype/customer/customer.py b/erpnext/selling/doctype/customer/customer.py index 18bd4432bd..4ddeae9e27 100644 --- a/erpnext/selling/doctype/customer/customer.py +++ b/erpnext/selling/doctype/customer/customer.py @@ -127,13 +127,13 @@ class Customer(TransactionBase): frappe.throw(_("A Customer Group exists with same name please change the Customer name or rename the Customer Group"), frappe.NameError) def validate_credit_limit_on_change(self): - customer = frappe.get_doc('Customer', self.name) - companies = [c.name for c in frappe.get_all("Company")] + if self.get("__islocal") or self.credit_limit == frappe.db.get_value("Customer", self.name, "credit_limit"): + return - for company in companies: - outstanding_amt = get_customer_outstanding(customer.name, company) + for company in frappe.get_all("Company"): + outstanding_amt = get_customer_outstanding(self.name, company.name) if flt(self.credit_limit) < outstanding_amt: - frappe.throw(_("New credit limit is less than current outstanding amount for the customer. Credit limit has to be atleast {0}").format(outstanding_amt)) + frappe.throw(_("""New credit limit is less than current outstanding amount for the customer. Credit limit has to be atleast {0}""").format(outstanding_amt)) def delete_customer_address(self): addresses = frappe.db.sql("""select name, lead from `tabAddress` diff --git a/erpnext/selling/doctype/customer/test_customer.py b/erpnext/selling/doctype/customer/test_customer.py index 9e53845f64..a76d3a146d 100644 --- a/erpnext/selling/doctype/customer/test_customer.py +++ b/erpnext/selling/doctype/customer/test_customer.py @@ -8,6 +8,7 @@ import unittest from frappe.test_runner import make_test_records from erpnext.exceptions import PartyFrozen, PartyDisabled +from frappe.utils import flt test_ignore = ["Price List"] @@ -111,6 +112,52 @@ class TestCustomer(unittest.TestCase): self.assertEquals("_Test Customer 1 - 1", duplicate_customer.name) self.assertEquals(test_customer_1.customer_name, duplicate_customer.customer_name) + def test_customer_credit_limit(self): + from erpnext.selling.doctype.customer.customer import get_credit_limit, get_customer_outstanding + from erpnext.stock.doctype.delivery_note.test_delivery_note import create_delivery_note + from erpnext.accounts.doctype.sales_invoice.test_sales_invoice import create_sales_invoice + from erpnext.selling.doctype.sales_order.test_sales_order import make_sales_order + from erpnext.selling.doctype.sales_order.sales_order import make_sales_invoice + + outstanding_amt = get_customer_outstanding('_Test Customer', '_Test Company') + credit_limit = get_credit_limit('_Test Customer', '_Test Company') + + + if credit_limit == 0.0: + frappe.db.set_value("Customer", '_Test Customer', 'credit_limit', 50.0) + + # Sales Order + so = make_sales_order(do_not_submit=True) + self.assertRaises(frappe.ValidationError, so.submit) + + # Delivery Note + dn = create_delivery_note(do_not_submit=True) + self.assertRaises(frappe.ValidationError, dn.submit) + + # Sales Invoice + si = create_sales_invoice(do_not_submit=True) + self.assertRaises(frappe.ValidationError, si.submit) + + if credit_limit > outstanding_amt: + frappe.db.set_value("Customer", '_Test Customer', 'credit_limit', credit_limit) + + # Makes Sales invoice from Sales Order + so.save(ignore_permissions=True) + si = make_sales_invoice(so.name) + si.save(ignore_permissions=True) + self.assertRaises(frappe.ValidationError, make_sales_order) + + def test_customer_credit_limit_on_change(self): + from erpnext.selling.doctype.customer.customer import get_credit_limit, get_customer_outstanding + from erpnext.selling.doctype.sales_order.test_sales_order import make_sales_order + + outstanding_amt = get_customer_outstanding('_Test Customer', '_Test Company') + credit_limit = get_credit_limit('_Test Customer', '_Test Company') + + customer = frappe.get_doc("Customer", '_Test Customer') + customer.credit_limit = flt(outstanding_amt - 100) + self.assertRaises(frappe.ValidationError, customer.save) + def get_customer_dict(customer_name): return { "customer_group": "_Test Customer Group", @@ -119,4 +166,3 @@ def get_customer_dict(customer_name): "doctype": "Customer", "territory": "_Test Territory" } - From f09929ea92eb5675d64b93749bd772414d447fa5 Mon Sep 17 00:00:00 2001 From: shreyas Date: Mon, 24 Oct 2016 10:35:30 +0530 Subject: [PATCH 3/4] [Fix] Updated test cases to handle negative or zero outstanding amount against customer --- .../selling/doctype/customer/test_customer.py | 20 ++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/erpnext/selling/doctype/customer/test_customer.py b/erpnext/selling/doctype/customer/test_customer.py index a76d3a146d..c671047865 100644 --- a/erpnext/selling/doctype/customer/test_customer.py +++ b/erpnext/selling/doctype/customer/test_customer.py @@ -112,6 +112,17 @@ class TestCustomer(unittest.TestCase): self.assertEquals("_Test Customer 1 - 1", duplicate_customer.name) self.assertEquals(test_customer_1.customer_name, duplicate_customer.customer_name) + def get_customer_outstanding_amount(self): + outstanding_amt = get_customer_outstanding('_Test Customer', '_Test Company') + + # If outstanding is negative make a transaction to get positive outstanding amount + if outstanding_amt > 0.0: + return outstanding_amt + + item_qty = int((abs(outstanding_amt) + 200)/100) + make_sales_order({'qty':item_qty}) + return get_customer_outstanding('_Test Customer', '_Test Company') + def test_customer_credit_limit(self): from erpnext.selling.doctype.customer.customer import get_credit_limit, get_customer_outstanding from erpnext.stock.doctype.delivery_note.test_delivery_note import create_delivery_note @@ -119,12 +130,15 @@ class TestCustomer(unittest.TestCase): from erpnext.selling.doctype.sales_order.test_sales_order import make_sales_order from erpnext.selling.doctype.sales_order.sales_order import make_sales_invoice - outstanding_amt = get_customer_outstanding('_Test Customer', '_Test Company') + outstanding_amt = self.get_customer_outstanding_amount() credit_limit = get_credit_limit('_Test Customer', '_Test Company') + if outstanding_amt <= 0.0: + item_qty = int((abs(outstanding_amt) + 200)/100) + make_sales_order({'qty':item_qty}) if credit_limit == 0.0: - frappe.db.set_value("Customer", '_Test Customer', 'credit_limit', 50.0) + frappe.db.set_value("Customer", '_Test Customer', 'credit_limit', outstanding_amt - 50.0) # Sales Order so = make_sales_order(do_not_submit=True) @@ -151,7 +165,7 @@ class TestCustomer(unittest.TestCase): from erpnext.selling.doctype.customer.customer import get_credit_limit, get_customer_outstanding from erpnext.selling.doctype.sales_order.test_sales_order import make_sales_order - outstanding_amt = get_customer_outstanding('_Test Customer', '_Test Company') + outstanding_amt = self.get_customer_outstanding_amount() credit_limit = get_credit_limit('_Test Customer', '_Test Company') customer = frappe.get_doc("Customer", '_Test Customer') From a221f7ec5deb682a29ad8fbd368394706b3bf301 Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Mon, 24 Oct 2016 11:27:56 +0530 Subject: [PATCH 4/4] Update test_customer.py --- erpnext/selling/doctype/customer/test_customer.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/erpnext/selling/doctype/customer/test_customer.py b/erpnext/selling/doctype/customer/test_customer.py index c671047865..36e4819ffe 100644 --- a/erpnext/selling/doctype/customer/test_customer.py +++ b/erpnext/selling/doctype/customer/test_customer.py @@ -9,6 +9,7 @@ import unittest from frappe.test_runner import make_test_records from erpnext.exceptions import PartyFrozen, PartyDisabled from frappe.utils import flt +from erpnext.selling.doctype.customer.customer import get_credit_limit, get_customer_outstanding test_ignore = ["Price List"] @@ -124,7 +125,6 @@ class TestCustomer(unittest.TestCase): return get_customer_outstanding('_Test Customer', '_Test Company') def test_customer_credit_limit(self): - from erpnext.selling.doctype.customer.customer import get_credit_limit, get_customer_outstanding from erpnext.stock.doctype.delivery_note.test_delivery_note import create_delivery_note from erpnext.accounts.doctype.sales_invoice.test_sales_invoice import create_sales_invoice from erpnext.selling.doctype.sales_order.test_sales_order import make_sales_order @@ -162,7 +162,6 @@ class TestCustomer(unittest.TestCase): self.assertRaises(frappe.ValidationError, make_sales_order) def test_customer_credit_limit_on_change(self): - from erpnext.selling.doctype.customer.customer import get_credit_limit, get_customer_outstanding from erpnext.selling.doctype.sales_order.test_sales_order import make_sales_order outstanding_amt = self.get_customer_outstanding_amount()