Merge branch 'ashish-greycube-feature_10861-1' into develop
diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py
index 53fba5b..6a54164 100644
--- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py
+++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py
@@ -989,4 +989,4 @@
 def set_account_for_mode_of_payment(self):
 	for data in self.payments:
 		if not data.account:
-			data.account = get_bank_cash_account(data.mode_of_payment, self.company).get("account")
+			data.account = get_bank_cash_account(data.mode_of_payment, self.company).get("account")
\ No newline at end of file
diff --git a/erpnext/domains/retail.py b/erpnext/domains/retail.py
index 1bfd65f..897c4d9 100644
--- a/erpnext/domains/retail.py
+++ b/erpnext/domains/retail.py
@@ -10,8 +10,7 @@
 		'ToDo'
 	],
 	'properties': [
-		{'doctype': 'Item', 'fieldname': 'manufacturing', 'property': 'hidden', 'value': 1},
-		{'doctype': 'Customer', 'fieldname': 'credit_limit_section', 'property': 'hidden', 'value': 1},
+		{'doctype': 'Item', 'fieldname': 'manufacturing', 'property': 'hidden', 'value': 1}
 	],
 	'set_value': [
 		['Stock Settings', None, 'show_barcode_field', 1]
diff --git a/erpnext/selling/doctype/customer/customer.json b/erpnext/selling/doctype/customer/customer.json
index 222d2e5..fd9d0a1 100644
--- a/erpnext/selling/doctype/customer/customer.json
+++ b/erpnext/selling/doctype/customer/customer.json
@@ -797,7 +797,7 @@
    "in_global_search": 0, 
    "in_list_view": 0, 
    "in_standard_filter": 0, 
-   "label": "Credit Limit", 
+   "label": "Credit Limit and Payment Terms", 
    "length": 0, 
    "no_copy": 0, 
    "permlevel": 0, 
@@ -810,7 +810,7 @@
    "search_index": 0, 
    "set_only_once": 0, 
    "unique": 0, 
-   "width": "50%"
+   "width": ""
   }, 
   {
    "allow_bulk_edit": 0, 
@@ -880,6 +880,37 @@
    "allow_bulk_edit": 0, 
    "allow_on_submit": 0, 
    "bold": 0, 
+   "collapsible": 0, 
+   "columns": 0, 
+   "default": "0", 
+   "fieldname": "bypass_credit_limit_check_at_sales_order", 
+   "fieldtype": "Check", 
+   "hidden": 0, 
+   "ignore_user_permissions": 0, 
+   "ignore_xss_filter": 0, 
+   "in_filter": 0, 
+   "in_global_search": 0, 
+   "in_list_view": 0, 
+   "in_standard_filter": 0, 
+   "label": "Bypass credit limit check at Sales Order", 
+   "length": 0, 
+   "no_copy": 0, 
+   "permlevel": 0, 
+   "precision": "", 
+   "print_hide": 0, 
+   "print_hide_if_no_value": 0, 
+   "read_only": 0, 
+   "remember_last_selected_value": 0, 
+   "report_hide": 0, 
+   "reqd": 0, 
+   "search_index": 0, 
+   "set_only_once": 0, 
+   "unique": 0
+  }, 
+  {
+   "allow_bulk_edit": 0, 
+   "allow_on_submit": 0, 
+   "bold": 0, 
    "collapsible": 1, 
    "collapsible_depends_on": "customer_details", 
    "columns": 0, 
@@ -1171,8 +1202,8 @@
  "issingle": 0, 
  "istable": 0, 
  "max_attachments": 0, 
- "modified": "2017-08-31 15:12:18.637132", 
- "modified_by": "tundebabzy@gmail.com", 
+ "modified": "2017-11-23 17:41:23.243421", 
+ "modified_by": "Administrator", 
  "module": "Selling", 
  "name": "Customer", 
  "name_case": "Title Case", 
diff --git a/erpnext/selling/doctype/customer/customer.py b/erpnext/selling/doctype/customer/customer.py
index 64cd190..a24f4a3 100644
--- a/erpnext/selling/doctype/customer/customer.py
+++ b/erpnext/selling/doctype/customer/customer.py
@@ -170,23 +170,30 @@
 			throw(_("Please contact to the user who have Sales Master Manager {0} role")
 				.format(" / " + credit_controller if credit_controller else ""))
 
-def get_customer_outstanding(customer, company):
+def get_customer_outstanding(customer, company, ignore_outstanding_sales_order=False):
 	# Outstanding based on GL Entries
-	outstanding_based_on_gle = frappe.db.sql("""select sum(debit) - sum(credit)
-		from `tabGL Entry` where party_type = 'Customer' and party = %s and company=%s""", (customer, company))
+	outstanding_based_on_gle = frappe.db.sql("""
+		select sum(debit) - sum(credit)
+		from `tabGL Entry`
+		where party_type = 'Customer' and party = %s and company=%s""", (customer, company))
 
 	outstanding_based_on_gle = flt(outstanding_based_on_gle[0][0]) if outstanding_based_on_gle else 0
 
 	# Outstanding based on Sales Order
-	outstanding_based_on_so = frappe.db.sql("""
-		select sum(base_grand_total*(100 - per_billed)/100)
-		from `tabSales Order`
-		where customer=%s and docstatus = 1 and company=%s
-		and per_billed < 100 and status != 'Closed'""", (customer, company))
+	outstanding_based_on_so = 0.0
 
-	outstanding_based_on_so = flt(outstanding_based_on_so[0][0]) if outstanding_based_on_so else 0.0
+	# if credit limit check is bypassed at sales order level,
+	# we should not consider outstanding Sales Orders, when customer credit balance report is run
+	if not ignore_outstanding_sales_order:
+		outstanding_based_on_so = frappe.db.sql("""
+			select sum(base_grand_total*(100 - per_billed)/100)
+			from `tabSales Order`
+			where customer=%s and docstatus = 1 and company=%s
+			and per_billed < 100 and status != 'Closed'""", (customer, company))
 
-	# Outstanding based on Delivery Note
+		outstanding_based_on_so = flt(outstanding_based_on_so[0][0]) if outstanding_based_on_so else 0.0
+
+	# Outstanding based on Delivery Note, which are not created against Sales Order
 	unmarked_delivery_note_items = frappe.db.sql("""select
 			dn_item.name, dn_item.amount, dn.base_net_total, dn.base_grand_total
 		from `tabDelivery Note` dn, `tabDelivery Note Item` dn_item
@@ -215,7 +222,8 @@
 	credit_limit = None
 
 	if customer:
-		credit_limit, customer_group = frappe.db.get_value("Customer", customer, ["credit_limit", "customer_group"])
+		credit_limit, customer_group = frappe.db.get_value("Customer",
+			customer, ["credit_limit", "customer_group"])
 
 		if not credit_limit:
 			credit_limit = frappe.db.get_value("Customer Group", customer_group, "credit_limit")
@@ -223,4 +231,4 @@
 	if not credit_limit:
 		credit_limit = frappe.db.get_value("Company", company, "credit_limit")
 
-	return flt(credit_limit)
+	return flt(credit_limit)
\ No newline at end of file
diff --git a/erpnext/selling/doctype/sales_order/sales_order.py b/erpnext/selling/doctype/sales_order/sales_order.py
index b3563c3..c9e7733 100644
--- a/erpnext/selling/doctype/sales_order/sales_order.py
+++ b/erpnext/selling/doctype/sales_order/sales_order.py
@@ -14,6 +14,7 @@
 from frappe.contacts.doctype.address.address import get_company_address
 from erpnext.controllers.selling_controller import SellingController
 from erpnext.accounts.doctype.subscription.subscription import get_next_schedule_date
+from erpnext.selling.doctype.customer.customer import check_credit_limit
 
 form_grid_templates = {
 	"items": "templates/form_grid/item_grid.html"
@@ -188,49 +189,68 @@
 	def update_project(self):
 		project_list = []
 		if self.project:
-				project = frappe.get_doc("Project", self.project)
-				project.flags.dont_sync_tasks = True
-				project.update_sales_costing()
-				project.save()
-				project_list.append(self.project)
+			project = frappe.get_doc("Project", self.project)
+			project.flags.dont_sync_tasks = True
+			project.update_sales_costing()
+			project.save()
+			project_list.append(self.project)
 
 	def check_credit_limit(self):
-		from erpnext.selling.doctype.customer.customer import check_credit_limit
-		check_credit_limit(self.customer, self.company)
+		# if bypass credit limit check is set to true (1) at sales order level,
+		# then we need not to check credit limit and vise versa
+		if not cint(frappe.db.get_value("Customer", self.customer, "bypass_credit_limit_check_at_sales_order")):
+			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
+		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:
-			frappe.throw(_("Delivery Notes {0} must be cancelled before cancelling this Sales Order").format(comma_and(submit_dn)))
+			frappe.throw(_("Delivery Notes {0} must be cancelled before cancelling this Sales Order")
+				.format(comma_and(submit_dn)))
 
 		# Checks Sales Invoice
 		submit_rv = frappe.db.sql_list("""select t1.name
 			from `tabSales Invoice` t1,`tabSales Invoice Item` t2
 			where t1.name = t2.parent and t2.sales_order = %s and t1.docstatus = 1""",
 			self.name)
+
 		if submit_rv:
-			frappe.throw(_("Sales Invoice {0} must be cancelled before cancelling this Sales Order").format(comma_and(submit_rv)))
+			frappe.throw(_("Sales Invoice {0} must be cancelled before cancelling this Sales Order")
+				.format(comma_and(submit_rv)))
 
 		#check maintenance schedule
-		submit_ms = frappe.db.sql_list("""select t1.name from `tabMaintenance Schedule` t1,
-			`tabMaintenance Schedule Item` t2
+		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:
-			frappe.throw(_("Maintenance Schedule {0} must be cancelled before cancelling this Sales Order").format(comma_and(submit_ms)))
+			frappe.throw(_("Maintenance Schedule {0} must be cancelled before cancelling this Sales Order")
+				.format(comma_and(submit_ms)))
 
 		# check maintenance visit
-		submit_mv = frappe.db.sql_list("""select t1.name from `tabMaintenance Visit` t1, `tabMaintenance Visit Purpose` t2
+		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:
-			frappe.throw(_("Maintenance Visit {0} must be cancelled before cancelling this Sales Order").format(comma_and(submit_mv)))
+			frappe.throw(_("Maintenance Visit {0} must be cancelled before cancelling this Sales Order")
+				.format(comma_and(submit_mv)))
 
 		# check production order
-		pro_order = frappe.db.sql_list("""select name from `tabProduction Order`
+		pro_order = frappe.db.sql_list("""
+			select name
+			from `tabProduction Order`
 			where sales_order = %s and docstatus = 1""", self.name)
+
 		if pro_order:
-			frappe.throw(_("Production Order {0} must be cancelled before cancelling this Sales Order").format(comma_and(pro_order)))
+			frappe.throw(_("Production Order {0} must be cancelled before cancelling this Sales Order")
+				.format(comma_and(pro_order)))
 
 	def check_modified_date(self):
 		mod_db = frappe.db.get_value("Sales Order", self.name, "modified")
@@ -464,6 +484,11 @@
 			else:
 				target.po_no = source.po_no
 
+		# Since the credit limit check is bypassed at sales order level,
+		# we need to check it at delivery note
+		if cint(frappe.db.get_value("Customer", source.customer, "bypass_credit_limit_check_at_sales_order")):
+			check_credit_limit(source.customer, source.company)
+
 		target.ignore_pricing_rule = 1
 		target.run_method("set_missing_values")
 		target.run_method("calculate_taxes_and_totals")
@@ -528,6 +553,10 @@
 		target.run_method("set_missing_values")
 		target.run_method("calculate_taxes_and_totals")
 
+		# Since the credit limit check is bypassed at sales order level, we need to check it at sales invoice
+		if cint(frappe.db.get_value("Customer", source.customer, "bypass_credit_limit_check_at_sales_order")):
+			check_credit_limit(source.customer, source.company)
+
 		# set company address
 		target.update(get_company_address(target.company))
 		if target.company_address:
@@ -791,4 +820,4 @@
 			order_by='is_default desc')
 	bom = bom[0].name if bom else None
 
-	return bom
+	return bom
\ No newline at end of file
diff --git a/erpnext/selling/doctype/sales_order/tests/test_sales_order_with_bypass_credit_limit_check.js b/erpnext/selling/doctype/sales_order/tests/test_sales_order_with_bypass_credit_limit_check.js
new file mode 100644
index 0000000..3ffb825
--- /dev/null
+++ b/erpnext/selling/doctype/sales_order/tests/test_sales_order_with_bypass_credit_limit_check.js
@@ -0,0 +1,54 @@
+QUnit.module('Sales Order');
+
+QUnit.test("test_sales_order_with_bypass_credit_limit_check", function(assert) {
+//#PR : 10861, Author : ashish-greycube & jigneshpshah,  Email:mr.ashish.shah@gmail.com 
+	assert.expect(2);
+	let done = assert.async();
+	frappe.run_serially([
+		() => frappe.new_doc('Customer'),
+		() => frappe.timeout(1),
+		() => frappe.click_link('Edit in full page'),
+		() => cur_frm.set_value("customer_name", "Test Customer 10"),
+		() => cur_frm.set_value("credit_limit", 100.00),
+		() => cur_frm.set_value("bypass_credit_limit_check_at_sales_order", 1),
+		// save form
+		() => cur_frm.save(),
+		() => frappe.timeout(1),
+
+		() => frappe.new_doc('Item'),
+		() => frappe.timeout(1),
+		() => frappe.click_link('Edit in full page'),
+		() => cur_frm.set_value("item_code", "Test Product 10"),
+		() => cur_frm.set_value("item_group", "Products"),
+		() => cur_frm.set_value("standard_rate", 100),	
+		// save form
+		() => cur_frm.save(),
+		() => frappe.timeout(1),		
+
+		() => {
+			return frappe.tests.make('Sales Order', [
+				{customer: 'Test Customer 5'},
+				{items: [
+					[
+						{'delivery_date': frappe.datetime.add_days(frappe.defaults.get_default("year_end_date"), 1)},
+						{'qty': 5},
+						{'item_code': 'Test Product 10'},
+					]
+				]}
+
+			]);
+		},
+		() => cur_frm.save(),
+		() => frappe.tests.click_button('Submit'),
+		() => assert.equal("Confirm", cur_dialog.title,'confirmation for submit'),
+		() => frappe.tests.click_button('Yes'),
+		() => frappe.timeout(3),
+		() => {
+			
+			assert.ok(cur_frm.doc.status=="To Deliver and Bill", "It is submited. Credit limit is NOT checked for sales order");
+
+
+		},		
+		() => done()
+	]);
+});
diff --git a/erpnext/selling/doctype/sales_order/tests/test_sales_order_without_bypass_credit_limit_check.js b/erpnext/selling/doctype/sales_order/tests/test_sales_order_without_bypass_credit_limit_check.js
new file mode 100644
index 0000000..ea15edc
--- /dev/null
+++ b/erpnext/selling/doctype/sales_order/tests/test_sales_order_without_bypass_credit_limit_check.js
@@ -0,0 +1,59 @@
+QUnit.module('Sales Order');
+
+QUnit.test("test_sales_order_without_bypass_credit_limit_check", function(assert) {
+//#PR : 10861, Author : ashish-greycube & jigneshpshah,  Email:mr.ashish.shah@gmail.com 
+	assert.expect(2);
+	let done = assert.async();
+	frappe.run_serially([
+		() => frappe.new_doc('Customer'),
+		() => frappe.timeout(1),
+		() => frappe.click_link('Edit in full page'),
+		() => cur_frm.set_value("customer_name", "Test Customer 11"),
+		() => cur_frm.set_value("credit_limit", 100.00),
+		() => cur_frm.set_value("bypass_credit_limit_check_at_sales_order", 0),
+		// save form
+		() => cur_frm.save(),
+		() => frappe.timeout(1),
+
+		() => frappe.new_doc('Item'),
+		() => frappe.timeout(1),
+		() => frappe.click_link('Edit in full page'),
+		() => cur_frm.set_value("item_code", "Test Product 11"),
+		() => cur_frm.set_value("item_group", "Products"),
+		() => cur_frm.set_value("standard_rate", 100),	
+		// save form
+		() => cur_frm.save(),
+		() => frappe.timeout(1),		
+
+		() => {
+			return frappe.tests.make('Sales Order', [
+				{customer: 'Test Customer 11'},
+				{items: [
+					[
+						{'delivery_date': frappe.datetime.add_days(frappe.defaults.get_default("year_end_date"), 1)},
+						{'qty': 5},
+						{'item_code': 'Test Product 11'},
+					]
+				]}
+
+			]);
+		},
+		() => cur_frm.save(),
+		() => frappe.tests.click_button('Submit'),
+		() => assert.equal("Confirm", cur_dialog.title,'confirmation for submit'),
+		() => frappe.tests.click_button('Yes'),
+		() => frappe.timeout(3),
+		() => {
+		
+			if (cur_dialog.body.innerText.match(/^Credit limit has been crossed for customer.*$/)) 
+				{ 
+    				/*Match found */
+    				assert.ok(true, "Credit Limit crossed message received");
+				}
+			
+	
+		},
+		() => cur_dialog.cancel(),
+		() => done()
+	]);
+});
diff --git a/erpnext/selling/report/customer_credit_balance/customer_credit_balance.py b/erpnext/selling/report/customer_credit_balance/customer_credit_balance.py
index 9075c3f..ffa4180 100644
--- a/erpnext/selling/report/customer_credit_balance/customer_credit_balance.py
+++ b/erpnext/selling/report/customer_credit_balance/customer_credit_balance.py
@@ -19,14 +19,19 @@
 
 	for d in customer_list:
 		row = []
-		outstanding_amt = get_customer_outstanding(d.name, filters.get("company"))
-		credit_limit = get_credit_limit(d.name, filters.get("company"))
+
+		outstanding_amt = get_customer_outstanding(d.name, filters.get("company"),
+			ignore_outstanding_sales_order=d.bypass_credit_limit_check_at_sales_order)
+
+		credit_limit = get_credit_limit(d.name, filters.get("company"))		
+
 		bal = flt(credit_limit) - flt(outstanding_amt)
 
 		if customer_naming_type == "Naming Series":
-			row = [d.name, d.customer_name, credit_limit, outstanding_amt, bal]
+			row = [d.name, d.customer_name, credit_limit, outstanding_amt, bal,
+				d.bypass_credit_limit_check_at_sales_order]
 		else:
-			row = [d.name, credit_limit, outstanding_amt, bal]
+			row = [d.name, credit_limit, outstanding_amt, bal, d.bypass_credit_limit_check_at_sales_order]
 
 		if credit_limit:
 			data.append(row)
@@ -35,8 +40,11 @@
 
 def get_columns(customer_naming_type):
 	columns = [
-		_("Customer") + ":Link/Customer:120", _("Credit Limit") + ":Currency:120",
-		_("Outstanding Amt") + ":Currency:100", _("Credit Balance") + ":Currency:120"
+		_("Customer") + ":Link/Customer:120",
+		_("Credit Limit") + ":Currency:120",
+		_("Outstanding Amt") + ":Currency:100",
+		_("Credit Balance") + ":Currency:120",
+		_("Bypass credit check at Sales Order ") + ":Check:240"
 	]
 
 	if customer_naming_type == "Naming Series":
@@ -50,5 +58,6 @@
 	if filters.get("customer"):
 		conditions += " where name = %(customer)s"
 
-	return frappe.db.sql("""select name, customer_name from `tabCustomer` %s""" 
-		% conditions, filters, as_dict=1)
+	return frappe.db.sql("""select name, customer_name,
+		bypass_credit_limit_check_at_sales_order from `tabCustomer` %s
+	""" % conditions, filters, as_dict=1)
\ No newline at end of file