Merge branch 'develop' into quoted-item-report-v2
diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.json b/erpnext/accounts/doctype/sales_invoice/sales_invoice.json
index 31613e5..2397b7d 100644
--- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.json
+++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.json
@@ -447,7 +447,7 @@
   {
    "allow_on_submit": 1,
    "fieldname": "po_no",
-   "fieldtype": "Small Text",
+   "fieldtype": "Data",
    "hide_days": 1,
    "hide_seconds": 1,
    "label": "Customer's Purchase Order",
@@ -1946,7 +1946,7 @@
  "idx": 181,
  "is_submittable": 1,
  "links": [],
- "modified": "2020-08-03 23:31:12.675040",
+ "modified": "2020-08-27 01:56:28.532140",
  "modified_by": "Administrator",
  "module": "Accounts",
  "name": "Sales Invoice",
diff --git a/erpnext/accounts/doctype/shipping_rule/shipping_rule.js b/erpnext/accounts/doctype/shipping_rule/shipping_rule.js
index 53ee08a..d0904ee 100644
--- a/erpnext/accounts/doctype/shipping_rule/shipping_rule.js
+++ b/erpnext/accounts/doctype/shipping_rule/shipping_rule.js
@@ -3,6 +3,22 @@
 
 frappe.ui.form.on('Shipping Rule', {
 	refresh: function(frm) {
+		frm.set_query("cost_center", function() {
+			return {
+				filters: {
+					company: frm.doc.company
+				}
+			}
+		})
+
+		frm.set_query("account", function() {
+			return {
+				filters: {
+					company: frm.doc.company
+				}
+			}
+		})
+
 		frm.trigger('toggle_reqd');
 	},
 	calculate_based_on: function(frm) {
@@ -12,4 +28,4 @@
 		frm.toggle_reqd("shipping_amount", frm.doc.calculate_based_on === 'Fixed');
 		frm.toggle_reqd("conditions", frm.doc.calculate_based_on !== 'Fixed');
 	}
-});
\ No newline at end of file
+});
diff --git a/erpnext/accounts/report/customer_ledger_summary/customer_ledger_summary.py b/erpnext/accounts/report/customer_ledger_summary/customer_ledger_summary.py
index 2cb10b1..10b32fe 100644
--- a/erpnext/accounts/report/customer_ledger_summary/customer_ledger_summary.py
+++ b/erpnext/accounts/report/customer_ledger_summary/customer_ledger_summary.py
@@ -173,7 +173,7 @@
 			from `tabGL Entry` gle
 			{join}
 			where
-				gle.docstatus < 2 and gle.party_type=%(party_type)s and ifnull(gle.party, '') != ''
+				gle.docstatus < 2 and gle.is_cancelled = 0 and gle.party_type=%(party_type)s and ifnull(gle.party, '') != ''
 				and gle.posting_date <= %(to_date)s {conditions}
 			order by gle.posting_date
 		""".format(join=join, join_field=join_field, conditions=conditions), self.filters, as_dict=True)
@@ -248,7 +248,7 @@
 			from
 				`tabGL Entry`
 			where
-				docstatus < 2
+				docstatus < 2 and is_cancelled = 0
 				and (voucher_type, voucher_no) in (
 					select voucher_type, voucher_no from `tabGL Entry` gle, `tabAccount` acc
 					where acc.name = gle.account and acc.account_type = '{income_or_expense}'
diff --git a/erpnext/controllers/buying_controller.py b/erpnext/controllers/buying_controller.py
index f982700..ac567b7 100644
--- a/erpnext/controllers/buying_controller.py
+++ b/erpnext/controllers/buying_controller.py
@@ -276,6 +276,9 @@
 		qty_to_be_received_map = get_qty_to_be_received(purchase_orders)
 
 		for item in self.get('items'):
+			if not item.purchase_order:
+				continue
+
 			# reset raw_material cost
 			item.rm_supp_cost = 0
 
@@ -288,6 +291,12 @@
 
 			fg_yet_to_be_received = qty_to_be_received_map.get(item_key)
 
+			if not fg_yet_to_be_received:
+				frappe.throw(_("Row #{0}: Item {1} is already fully received in Purchase Order {2}")
+					.format(item.idx, frappe.bold(item.item_code),
+						frappe.utils.get_link_to_form("Purchase Order", item.purchase_order)),
+					title=_("Limit Crossed"))
+
 			transferred_batch_qty_map = get_transferred_batch_qty_map(item.purchase_order, item.item_code)
 			backflushed_batch_qty_map = get_backflushed_batch_qty_map(item.purchase_order, item.item_code)
 
diff --git a/erpnext/controllers/taxes_and_totals.py b/erpnext/controllers/taxes_and_totals.py
index 2a14be8..92cfdb7 100644
--- a/erpnext/controllers/taxes_and_totals.py
+++ b/erpnext/controllers/taxes_and_totals.py
@@ -9,6 +9,7 @@
 from erpnext.controllers.accounts_controller import validate_conversion_rate, \
 	validate_taxes_and_charges, validate_inclusive_tax
 from erpnext.stock.get_item_details import _get_item_tax_template
+from erpnext.accounts.doctype.pricing_rule.utils import get_applied_pricing_rules
 
 class calculate_taxes_and_totals(object):
 	def __init__(self, doc):
@@ -209,7 +210,7 @@
 			elif tax.charge_type == "On Previous Row Total":
 				current_tax_fraction = (tax_rate / 100.0) * \
 					self.doc.get("taxes")[cint(tax.row_id) - 1].grand_total_fraction_for_current_item
-			
+
 			elif tax.charge_type == "On Item Quantity":
 				inclusive_tax_amount_per_qty = flt(tax_rate)
 
@@ -607,7 +608,7 @@
 		base_rate_with_margin = 0.0
 		if item.price_list_rate:
 			if item.pricing_rules and not self.doc.ignore_pricing_rule:
-				for d in json.loads(item.pricing_rules):
+				for d in get_applied_pricing_rules(item.pricing_rules):
 					pricing_rule = frappe.get_cached_doc('Pricing Rule', d)
 
 					if (pricing_rule.margin_type == 'Amount' and pricing_rule.currency == self.doc.currency)\
diff --git a/erpnext/healthcare/doctype/patient_appointment/patient_appointment.js b/erpnext/healthcare/doctype/patient_appointment/patient_appointment.js
index f7ed31b..2d6b645 100644
--- a/erpnext/healthcare/doctype/patient_appointment/patient_appointment.js
+++ b/erpnext/healthcare/doctype/patient_appointment/patient_appointment.js
@@ -226,7 +226,9 @@
 			primary_action_label: __('Book'),
 			primary_action: function() {
 				frm.set_value('appointment_time', selected_slot);
-				frm.set_value('duration', duration);
+				if (!frm.doc.duration) {
+					frm.set_value('duration', duration);
+				}
 				frm.set_value('practitioner', d.get_value('practitioner'));
 				frm.set_value('department', d.get_value('department'));
 				frm.set_value('appointment_date', d.get_value('appointment_date'));
diff --git a/erpnext/manufacturing/doctype/bom_update_tool/bom_update_tool.py b/erpnext/manufacturing/doctype/bom_update_tool/bom_update_tool.py
index e6c10ad..742d18c 100644
--- a/erpnext/manufacturing/doctype/bom_update_tool/bom_update_tool.py
+++ b/erpnext/manufacturing/doctype/bom_update_tool/bom_update_tool.py
@@ -90,6 +90,7 @@
 		update_cost()
 
 def replace_bom(args):
+	frappe.db.auto_commit_on_many_writes = 1
 	args = frappe._dict(args)
 
 	doc = frappe.get_doc("BOM Update Tool")
@@ -97,6 +98,8 @@
 	doc.new_bom = args.new_bom
 	doc.replace_bom()
 
+	frappe.db.auto_commit_on_many_writes = 0
+
 def update_cost():
 	frappe.db.auto_commit_on_many_writes = 1
 	bom_list = get_boms_in_bottom_up_order()
diff --git a/erpnext/patches.txt b/erpnext/patches.txt
index e17e949..a8648f5 100644
--- a/erpnext/patches.txt
+++ b/erpnext/patches.txt
@@ -718,6 +718,7 @@
 erpnext.patches.v12_0.update_item_tax_template_company
 erpnext.patches.v13_0.move_branch_code_to_bank_account
 erpnext.patches.v13_0.healthcare_lab_module_rename_doctypes
+erpnext.patches.v13_0.add_standard_navbar_items #4
 erpnext.patches.v13_0.stock_entry_enhancements
 erpnext.patches.v12_0.update_state_code_for_daman_and_diu
 erpnext.patches.v12_0.rename_lost_reason_detail
diff --git a/erpnext/patches/v13_0/add_standard_navbar_items.py b/erpnext/patches/v13_0/add_standard_navbar_items.py
new file mode 100644
index 0000000..d05b258
--- /dev/null
+++ b/erpnext/patches/v13_0/add_standard_navbar_items.py
@@ -0,0 +1,7 @@
+from __future__ import unicode_literals
+# import frappe
+from erpnext.setup.install import add_standard_navbar_items
+
+def execute():
+	# Add standard navbar items for ERPNext in Navbar Settings
+	add_standard_navbar_items()
diff --git a/erpnext/public/js/conf.js b/erpnext/public/js/conf.js
index 9870f81..2af9140 100644
--- a/erpnext/public/js/conf.js
+++ b/erpnext/public/js/conf.js
@@ -3,32 +3,6 @@
 
 frappe.provide('erpnext');
 
-// add toolbar icon
-$(document).bind('toolbar_setup', function() {
-	frappe.app.name = "ERPNext";
-
-	frappe.help_feedback_link = '<p><a class="text-muted" \
-		href="https://discuss.erpnext.com">Feedback</a></p>'
-
-
-	$('[data-link="docs"]').attr("href", "https://erpnext.com/docs")
-	$('[data-link="issues"]').attr("href", "https://github.com/frappe/erpnext/issues")
-
-
-	// default documentation goes to erpnext
-	// $('[data-link-type="documentation"]').attr('data-path', '/erpnext/manual/index');
-
-	// additional help links for erpnext
-	var $help_menu = $('.dropdown-help ul .documentation-links');
-	$('<li><a data-link-type="forum" href="https://erpnext.com/docs/user/manual" \
-		target="_blank">'+__('Documentation')+'</a></li>').insertBefore($help_menu);
-	$('<li><a data-link-type="forum" href="https://discuss.erpnext.com" \
-		target="_blank">'+__('User Forum')+'</a></li>').insertBefore($help_menu);
-	$('<li><a href="https://github.com/frappe/erpnext/issues" \
-		target="_blank">'+__('Report an Issue')+'</a></li>').insertBefore($help_menu);
-
-});
-
 // preferred modules for breadcrumbs
 $.extend(frappe.breadcrumbs.preferred, {
 	"Item Group": "Stock",
diff --git a/erpnext/selling/doctype/customer/customer_dashboard.py b/erpnext/selling/doctype/customer/customer_dashboard.py
index cf23465..532c11b 100644
--- a/erpnext/selling/doctype/customer/customer_dashboard.py
+++ b/erpnext/selling/doctype/customer/customer_dashboard.py
@@ -33,7 +33,7 @@
 			},
 			{
 				'label': _('Support'),
-				'items': ['Issue', 'Maintenance Visit']
+				'items': ['Issue', 'Maintenance Visit', 'Installation Note', 'Warranty Claim']
 			},
 			{
 				'label': _('Projects'),
diff --git a/erpnext/selling/doctype/quotation/quotation.py b/erpnext/selling/doctype/quotation/quotation.py
index ab095eb..20ae19f 100644
--- a/erpnext/selling/doctype/quotation/quotation.py
+++ b/erpnext/selling/doctype/quotation/quotation.py
@@ -285,9 +285,17 @@
 						return customer
 					else:
 						raise
-				except frappe.MandatoryError:
+				except frappe.MandatoryError as e:
+					mandatory_fields = e.args[0].split(':')[1].split(',')
+					mandatory_fields = [customer.meta.get_label(field.strip()) for field in mandatory_fields]
+
 					frappe.local.message_log = []
-					frappe.throw(_("Please create Customer from Lead {0}").format(lead_name))
+					lead_link = frappe.utils.get_link_to_form("Lead", lead_name)
+					message = _("Could not auto create Customer due to the following missing mandatory field(s):") + "<br>"
+					message += "<br><ul><li>" + "</li><li>".join(mandatory_fields) + "</li></ul>"
+					message += _("Please create Customer from Lead {0}.").format(lead_link)
+
+					frappe.throw(message, title=_("Mandatory Missing"))
 			else:
 				return customer_name
 		else:
diff --git a/erpnext/selling/page/point_of_sale/pos_item_cart.js b/erpnext/selling/page/point_of_sale/pos_item_cart.js
index c23a6ad..eadeb8f 100644
--- a/erpnext/selling/page/point_of_sale/pos_item_cart.js
+++ b/erpnext/selling/page/point_of_sale/pos_item_cart.js
@@ -356,7 +356,7 @@
 				onchange: function() {
 					if (this.value || this.value == 0) {
 						const frm = me.events.get_frm();
-						frappe.model.set_value(frm.doc.doctype, frm.doc.name, 'additional_discount_percentage', this.value);
+						frappe.model.set_value(frm.doc.doctype, frm.doc.name, 'additional_discount_percentage', flt(this.value));
 						me.hide_discount_control(this.value);
 					}
 				},
@@ -948,4 +948,4 @@
 		show ? this.$component.removeClass('d-none') : this.$component.addClass('d-none');
     }
     
-}
\ No newline at end of file
+}
diff --git a/erpnext/setup/doctype/company/delete_company_transactions.py b/erpnext/setup/doctype/company/delete_company_transactions.py
index 8ecc13b..c94831e 100644
--- a/erpnext/setup/doctype/company/delete_company_transactions.py
+++ b/erpnext/setup/doctype/company/delete_company_transactions.py
@@ -26,7 +26,8 @@
 		tabDocField where fieldtype='Link' and options='Company'"""):
 		if doctype not in ("Account", "Cost Center", "Warehouse", "Budget",
 			"Party Account", "Employee", "Sales Taxes and Charges Template",
-			"Purchase Taxes and Charges Template", "POS Profile", 'BOM'):
+			"Purchase Taxes and Charges Template", "POS Profile", "BOM",
+			"Company", "Bank Account"):
 				delete_for_doctype(doctype, company_name)
 
 	# reset company values
diff --git a/erpnext/setup/install.py b/erpnext/setup/install.py
index 50f9d84..4f0f572 100644
--- a/erpnext/setup/install.py
+++ b/erpnext/setup/install.py
@@ -26,6 +26,7 @@
 	create_default_success_action()
 	create_default_energy_point_rules()
 	add_company_to_session_defaults()
+	add_standard_navbar_items()
 	frappe.db.commit()
 
 
@@ -104,3 +105,45 @@
 		"ref_doctype": "Company"
 	})
 	settings.save()
+
+def add_standard_navbar_items():
+	navbar_settings = frappe.get_single("Navbar Settings")
+
+	erpnext_navbar_items = [
+		{
+			'item_label': 'Documentation',
+			'item_type': 'Route',
+			'route': 'https://erpnext.com/docs/user/manual',
+			'is_standard': 1
+		},
+		{
+			'item_label': 'User Forum',
+			'item_type': 'Route',
+			'route': 'https://discuss.erpnext.com',
+			'is_standard': 1
+		},
+		{
+			'item_label': 'Report an Issue',
+			'item_type': 'Route',
+			'route': 'https://github.com/frappe/erpnext/issues',
+			'is_standard': 1
+		}
+	]
+
+	current_nabvar_items = navbar_settings.help_dropdown
+	navbar_settings.set('help_dropdown', [])
+
+	for item in erpnext_navbar_items:
+		navbar_settings.append('help_dropdown', item)
+
+	for item in current_nabvar_items:
+		navbar_settings.append('help_dropdown', {
+			'item_label': item.item_label,
+			'item_type': item.item_type,
+			'route': item.route,
+			'action': item.action,
+			'is_standard': item.is_standard,
+			'hidden': item.hidden
+		})
+
+	navbar_settings.save()
diff --git a/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py b/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py
index 4a8236d..67161aa 100644
--- a/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py
+++ b/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py
@@ -3,6 +3,7 @@
 
 from __future__ import unicode_literals
 import unittest
+import json
 import frappe, erpnext
 import frappe.defaults
 from frappe.utils import cint, flt, cstr, today, random_string
@@ -152,13 +153,78 @@
 			qty=100, basic_rate=100, company="_Test Company with perpetual inventory")
 		pr = make_purchase_receipt(item_code="_Test FG Item", qty=10, rate=0, is_subcontracted="Yes",
 			company="_Test Company with perpetual inventory", warehouse='Stores - TCP1', supplier_warehouse='Work In Progress - TCP1')
-		
+
 		gl_entries = get_gl_entries("Purchase Receipt", pr.name)
 
 		self.assertFalse(gl_entries)
 
 		set_perpetual_inventory(0)
 
+	def test_subcontracting_over_receipt(self):
+		"""
+			Behaviour: Raise multiple PRs against one PO that in total
+				receive more than the required qty in the PO.
+			Expected Result: Error Raised for Over Receipt against PO.
+		"""
+		from erpnext.stock.doctype.stock_entry.test_stock_entry import make_stock_entry
+		from erpnext.buying.doctype.purchase_order.test_purchase_order import (update_backflush_based_on,
+			make_subcontracted_item, create_purchase_order)
+		from erpnext.buying.doctype.purchase_order.purchase_order import (make_purchase_receipt,
+			make_rm_stock_entry as make_subcontract_transfer_entry)
+
+		update_backflush_based_on("Material Transferred for Subcontract")
+		item_code = "_Test Subcontracted FG Item 1"
+		make_subcontracted_item(item_code)
+
+		po = create_purchase_order(item_code=item_code, qty=1,
+			is_subcontracted="Yes", supplier_warehouse="_Test Warehouse 1 - _TC")
+
+		#stock raw materials in a warehouse before transfer
+		make_stock_entry(target="_Test Warehouse - _TC",
+			item_code="_Test Item Home Desktop 100", qty=1, basic_rate=100)
+		make_stock_entry(target="_Test Warehouse - _TC",
+			item_code = "Test Extra Item 1", qty=1, basic_rate=100)
+		make_stock_entry(target="_Test Warehouse - _TC",
+			item_code = "_Test Item", qty=1, basic_rate=100)
+
+		rm_items = [
+			{
+				"item_code": item_code,
+				"rm_item_code": po.supplied_items[0].rm_item_code,
+				"item_name": "_Test Item",
+				"qty": po.supplied_items[0].required_qty,
+				"warehouse": "_Test Warehouse - _TC",
+				"stock_uom": "Nos"
+			},
+			{
+				"item_code": item_code,
+				"rm_item_code": po.supplied_items[1].rm_item_code,
+				"item_name": "Test Extra Item 1",
+				"qty": po.supplied_items[1].required_qty,
+				"warehouse": "_Test Warehouse - _TC",
+				"stock_uom": "Nos"
+			},
+			{
+				"item_code": item_code,
+				"rm_item_code": po.supplied_items[2].rm_item_code,
+				"item_name": "_Test Item Home Desktop 100",
+				"qty": po.supplied_items[2].required_qty,
+				"warehouse": "_Test Warehouse - _TC",
+				"stock_uom": "Nos"
+			}
+		]
+		rm_item_string = json.dumps(rm_items)
+		se = frappe.get_doc(make_subcontract_transfer_entry(po.name, rm_item_string))
+		se.to_warehouse = "_Test Warehouse 1 - _TC"
+		se.save()
+		se.submit()
+
+		pr1 = make_purchase_receipt(po.name)
+		pr2 = make_purchase_receipt(po.name)
+
+		pr1.submit()
+		self.assertRaises(frappe.ValidationError, pr2.submit)
+
 	def test_serial_no_supplier(self):
 		pr = make_purchase_receipt(item_code="_Test Serialized Item With Series", qty=1)
 		self.assertEqual(frappe.db.get_value("Serial No", pr.get("items")[0].serial_no, "supplier"),
diff --git a/erpnext/templates/generators/item/item_inquiry.js b/erpnext/templates/generators/item/item_inquiry.js
index 52ddae2..e7db3a3 100644
--- a/erpnext/templates/generators/item/item_inquiry.js
+++ b/erpnext/templates/generators/item/item_inquiry.js
@@ -22,6 +22,13 @@
 			},
 			{
 				fieldtype: 'Data',
+				label: __('Phone Number'),
+				fieldname: 'phone',
+				options: 'Phone',
+				reqd: 1
+			},
+			{
+				fieldtype: 'Data',
 				label: __('Subject'),
 				fieldname: 'subject',
 				reqd: 1