feat: Remove Leaderboard from ERPNext (#19156)

feat: remove Leaderboard from ERPNext
diff --git a/erpnext/crm/doctype/opportunity/opportunity.json b/erpnext/crm/doctype/opportunity/opportunity.json
index 37f492e..66e3ca4 100644
--- a/erpnext/crm/doctype/opportunity/opportunity.json
+++ b/erpnext/crm/doctype/opportunity/opportunity.json
@@ -1,5 +1,6 @@
 {
  "allow_import": 1,
+ "allow_rename": 1,
  "autoname": "naming_series:",
  "creation": "2013-03-07 18:50:30",
  "description": "Potential Sales Deal",
@@ -411,7 +412,7 @@
  ],
  "icon": "fa fa-info-sign",
  "idx": 195,
- "modified": "2019-09-12 09:37:30.127901",
+ "modified": "2019-09-30 12:58:37.385400",
  "modified_by": "Administrator",
  "module": "CRM",
  "name": "Opportunity",
diff --git a/erpnext/healthcare/doctype/patient/patient.json b/erpnext/healthcare/doctype/patient/patient.json
index 1de4205..0136f72 100644
--- a/erpnext/healthcare/doctype/patient/patient.json
+++ b/erpnext/healthcare/doctype/patient/patient.json
@@ -347,7 +347,7 @@
  "icon": "fa fa-user",
  "image_field": "image",
  "max_attachments": 50,
- "modified": "2019-09-23 16:01:39.811633",
+ "modified": "2019-09-25 23:30:49.905893",
  "modified_by": "Administrator",
  "module": "Healthcare",
  "name": "Patient",
@@ -362,6 +362,18 @@
    "print": 1,
    "read": 1,
    "report": 1,
+   "role": "System Manager",
+   "share": 1,
+   "write": 1
+  },
+  {
+   "create": 1,
+   "delete": 1,
+   "email": 1,
+   "export": 1,
+   "print": 1,
+   "read": 1,
+   "report": 1,
    "role": "Physician",
    "share": 1,
    "write": 1
diff --git a/erpnext/projects/doctype/project/project.json b/erpnext/projects/doctype/project/project.json
index 205f895..7d47db3 100644
--- a/erpnext/projects/doctype/project/project.json
+++ b/erpnext/projects/doctype/project/project.json
@@ -108,7 +108,7 @@
    "fieldname": "percent_complete_method",
    "fieldtype": "Select",
    "label": "% Complete Method",
-   "options": "Task Completion\nTask Progress\nTask Weight"
+   "options": "Manual\nTask Completion\nTask Progress\nTask Weight"
   },
   {
    "bold": 1,
diff --git a/erpnext/projects/doctype/project/project.py b/erpnext/projects/doctype/project/project.py
index 6176cf8..783bcf3 100644
--- a/erpnext/projects/doctype/project/project.py
+++ b/erpnext/projects/doctype/project/project.py
@@ -87,6 +87,11 @@
 			frappe.db.set_value("Sales Order", self.sales_order, "project", self.name)
 
 	def update_percent_complete(self):
+		if self.percent_complete_method == "Manual":
+			if self.status == "Completed":
+				self.percent_complete = 100
+			return
+
 		total = frappe.db.count('Task', dict(project=self.name))
 
 		if not total:
diff --git a/erpnext/setup/doctype/company/company.py b/erpnext/setup/doctype/company/company.py
index 584391e..9eb3748 100644
--- a/erpnext/setup/doctype/company/company.py
+++ b/erpnext/setup/doctype/company/company.py
@@ -64,16 +64,19 @@
 		})
 
 	def validate_default_accounts(self):
-		for field in ["default_bank_account", "default_cash_account",
+		accounts = [
+			"default_bank_account", "default_cash_account",
 			"default_receivable_account", "default_payable_account",
 			"default_expense_account", "default_income_account",
 			"stock_received_but_not_billed", "stock_adjustment_account",
-			"expenses_included_in_valuation", "default_payroll_payable_account"]:
-				if self.get(field):
-					for_company = frappe.db.get_value("Account", self.get(field), "company")
-					if for_company != self.name:
-						frappe.throw(_("Account {0} does not belong to company: {1}")
-							.format(self.get(field), self.name))
+			"expenses_included_in_valuation", "default_payroll_payable_account"
+		]
+
+		for field in accounts:
+			if self.get(field):
+				for_company = frappe.db.get_value("Account", self.get(field), "company")
+				if for_company != self.name:
+					frappe.throw(_("Account {0} does not belong to company: {1}").format(self.get(field), self.name))
 
 	def validate_currency(self):
 		if self.is_new():
@@ -180,21 +183,29 @@
 			self.existing_company = self.parent_company
 
 	def set_default_accounts(self):
-		self._set_default_account("default_cash_account", "Cash")
-		self._set_default_account("default_bank_account", "Bank")
-		self._set_default_account("round_off_account", "Round Off")
-		self._set_default_account("accumulated_depreciation_account", "Accumulated Depreciation")
-		self._set_default_account("depreciation_expense_account", "Depreciation")
-		self._set_default_account("capital_work_in_progress_account", "Capital Work in Progress")
-		self._set_default_account("asset_received_but_not_billed", "Asset Received But Not Billed")
-		self._set_default_account("expenses_included_in_asset_valuation", "Expenses Included In Asset Valuation")
+		default_accounts = {
+			"default_cash_account": "Cash",
+			"default_bank_account": "Bank",
+			"round_off_account": "Round Off",
+			"accumulated_depreciation_account": "Accumulated Depreciation",
+			"depreciation_expense_account": "Depreciation",
+			"capital_work_in_progress_account": "Capital Work in Progress",
+			"asset_received_but_not_billed": "Asset Received But Not Billed",
+			"expenses_included_in_asset_valuation": "Expenses Included In Asset Valuation"
+		}
 
 		if self.enable_perpetual_inventory:
-			self._set_default_account("stock_received_but_not_billed", "Stock Received But Not Billed")
-			self._set_default_account("default_inventory_account", "Stock")
-			self._set_default_account("stock_adjustment_account", "Stock Adjustment")
-			self._set_default_account("expenses_included_in_valuation", "Expenses Included In Valuation")
-			self._set_default_account("default_expense_account", "Cost of Goods Sold")
+			default_accounts.update({
+				"stock_received_but_not_billed": "Stock Received But Not Billed",
+				"default_inventory_account": "Stock",
+				"stock_adjustment_account": "Stock Adjustment",
+				"expenses_included_in_valuation": "Expenses Included In Valuation",
+				"default_expense_account": "Cost of Goods Sold"
+			})
+
+		for default_account in default_accounts:
+			if self.is_new() or frappe.flags.in_test:
+				self._set_default_account(default_account, default_accounts.get(default_account))
 
 		if not self.default_income_account:
 			income_account = frappe.db.get_value("Account",
@@ -243,8 +254,7 @@
 		if self.get(fieldname):
 			return
 
-		account = frappe.db.get_value("Account", {"account_type": account_type,
-			"is_group": 0, "company": self.name})
+		account = frappe.db.get_value("Account", {"account_type": account_type, "is_group": 0, "company": self.name})
 
 		if account:
 			self.db_set(fieldname, account)
diff --git a/erpnext/stock/report/stock_ledger/stock_ledger.py b/erpnext/stock/report/stock_ledger/stock_ledger.py
index d386230..5bdbca2 100644
--- a/erpnext/stock/report/stock_ledger/stock_ledger.py
+++ b/erpnext/stock/report/stock_ledger/stock_ledger.py
@@ -107,7 +107,7 @@
 	if include_uom:
 		cf_field = ", ucd.conversion_factor"
 		cf_join = "left join `tabUOM Conversion Detail` ucd on ucd.parent=item.name and ucd.uom='%s'" \
-			% frappe.db.escape(include_uom)
+			% (include_uom)
 
 	res = frappe.db.sql("""
 		select
diff --git a/erpnext/stock/utils.py b/erpnext/stock/utils.py
index 4c663e3..2ac0bae 100644
--- a/erpnext/stock/utils.py
+++ b/erpnext/stock/utils.py
@@ -253,31 +253,40 @@
 		return
 
 	convertible_cols = {}
-	for col_idx in reversed(range(0, len(columns))):
-		col = columns[col_idx]
-		if isinstance(col, dict) and col.get("convertible") in ['rate', 'qty']:
-			convertible_cols[col_idx] = col['convertible']
-			columns.insert(col_idx+1, col.copy())
-			columns[col_idx+1]['fieldname'] += "_alt"
-			if convertible_cols[col_idx] == 'rate':
-				columns[col_idx+1]['label'] += " (per {})".format(include_uom)
-			else:
-				columns[col_idx+1]['label'] += " ({})".format(include_uom)
+
+	is_dict_obj = False
+	if isinstance(result[0], dict):
+		is_dict_obj = True
+
+	convertible_columns = {}
+	for idx, d in enumerate(columns):
+		key = d.get("fieldname") if is_dict_obj else idx
+		if d.get("convertible"):
+			convertible_columns.setdefault(key, d.get("convertible"))
+
+			# Add new column to show qty/rate as per the selected UOM
+			columns.insert(idx+1, {
+				'label': "{0} (per {1})".format(d.get("label"), include_uom),
+				'fieldname': "{0}_{1}".format(d.get("fieldname"), frappe.scrub(include_uom)),
+				'fieldtype': 'Currency' if d.get("convertible") == 'rate' else 'Float'
+			})
 
 	for row_idx, row in enumerate(result):
-		new_row = []
-		for col_idx, d in enumerate(row):
-			new_row.append(d)
-			if col_idx in convertible_cols:
-				if conversion_factors[row_idx]:
-					if convertible_cols[col_idx] == 'rate':
-						new_row.append(flt(d) * conversion_factors[row_idx])
-					else:
-						new_row.append(flt(d) / conversion_factors[row_idx])
-				else:
-					new_row.append(None)
+		data = row.items() if is_dict_obj else enumerate(row)
+		for key, value in data:
+			if not key in convertible_columns or not conversion_factors[row_idx]:
+				continue
 
-		result[row_idx] = new_row
+			if convertible_columns.get(key) == 'rate':
+				new_value = flt(value) * conversion_factors[row_idx]
+			else:
+				new_value = flt(value) / conversion_factors[row_idx]
+
+			if not is_dict_obj:
+				row.insert(key+1, new_value)
+			else:
+				new_key = "{0}_{1}".format(key, frappe.scrub(include_uom))
+				row[new_key] = new_value
 
 def get_available_serial_nos(item_code, warehouse):
 	return frappe.get_all("Serial No", filters = {'item_code': item_code,