Merge pull request #21476 from deepeshgarg007/duplicate_code

fix: Remove duplicate code from accounting dimension
diff --git a/erpnext/accounts/report/consolidated_financial_statement/consolidated_financial_statement.py b/erpnext/accounts/report/consolidated_financial_statement/consolidated_financial_statement.py
index b62238b..c2c7207 100644
--- a/erpnext/accounts/report/consolidated_financial_statement/consolidated_financial_statement.py
+++ b/erpnext/accounts/report/consolidated_financial_statement/consolidated_financial_statement.py
@@ -84,6 +84,7 @@
 
 def get_profit_loss_data(fiscal_year, companies, columns, filters):
 	income, expense, net_profit_loss = get_income_expense_data(companies, fiscal_year, filters)
+	company_currency = get_company_currency(filters)
 
 	data = []
 	data.extend(income or [])
@@ -93,7 +94,7 @@
 
 	chart = get_pl_chart_data(filters, columns, income, expense, net_profit_loss)
 
-	report_summary = get_pl_summary(companies, '', income, expense, net_profit_loss, True)
+	report_summary = get_pl_summary(companies, '', income, expense, net_profit_loss, company_currency, True)
 
 	return data, None, chart, report_summary
 
diff --git a/erpnext/accounts/report/gross_profit/gross_profit.py b/erpnext/accounts/report/gross_profit/gross_profit.py
index 6ef6d6e..4e22b05 100644
--- a/erpnext/accounts/report/gross_profit/gross_profit.py
+++ b/erpnext/accounts/report/gross_profit/gross_profit.py
@@ -55,27 +55,27 @@
 	columns = []
 	column_map = frappe._dict({
 		"parent": _("Sales Invoice") + ":Link/Sales Invoice:120",
-		"posting_date": _("Posting Date") + ":Date",
-		"posting_time": _("Posting Time"),
-		"item_code": _("Item Code") + ":Link/Item",
-		"item_name": _("Item Name"),
-		"item_group": _("Item Group") + ":Link/Item Group",
-		"brand": _("Brand"),
-		"description": _("Description"),
-		"warehouse": _("Warehouse") + ":Link/Warehouse",
-		"qty": _("Qty") + ":Float",
-		"base_rate": _("Avg. Selling Rate") + ":Currency/currency",
-		"buying_rate": _("Valuation Rate") + ":Currency/currency",
-		"base_amount": _("Selling Amount") + ":Currency/currency",
-		"buying_amount": _("Buying Amount") + ":Currency/currency",
-		"gross_profit": _("Gross Profit") + ":Currency/currency",
-		"gross_profit_percent": _("Gross Profit %") + ":Percent",
-		"project": _("Project") + ":Link/Project",
+		"posting_date": _("Posting Date") + ":Date:100",
+		"posting_time": _("Posting Time") + ":Data:100",
+		"item_code": _("Item Code") + ":Link/Item:100",
+		"item_name": _("Item Name") + ":Data:100",
+		"item_group": _("Item Group") + ":Link/Item Group:100",
+		"brand": _("Brand") + ":Link/Brand:100",
+		"description": _("Description") +":Data:100",
+		"warehouse": _("Warehouse") + ":Link/Warehouse:100",
+		"qty": _("Qty") + ":Float:80",
+		"base_rate": _("Avg. Selling Rate") + ":Currency/currency:100",
+		"buying_rate": _("Valuation Rate") + ":Currency/currency:100",
+		"base_amount": _("Selling Amount") + ":Currency/currency:100",
+		"buying_amount": _("Buying Amount") + ":Currency/currency:100",
+		"gross_profit": _("Gross Profit") + ":Currency/currency:100",
+		"gross_profit_percent": _("Gross Profit %") + ":Percent:100",
+		"project": _("Project") + ":Link/Project:100",
 		"sales_person": _("Sales person"),
-		"allocated_amount": _("Allocated Amount") + ":Currency/currency",
-		"customer": _("Customer") + ":Link/Customer",
-		"customer_group": _("Customer Group") + ":Link/Customer Group",
-		"territory": _("Territory") + ":Link/Territory"
+		"allocated_amount": _("Allocated Amount") + ":Currency/currency:100",
+		"customer": _("Customer") + ":Link/Customer:100",
+		"customer_group": _("Customer Group") + ":Link/Customer Group:100",
+		"territory": _("Territory") + ":Link/Territory:100"
 	})
 
 	for col in group_wise_columns.get(scrub(filters.group_by)):
@@ -85,7 +85,8 @@
 		"fieldname": "currency",
 		"label" : _("Currency"),
 		"fieldtype": "Link",
-		"options": "Currency"
+		"options": "Currency",
+		"hidden": 1
 	})
 
 	return columns
@@ -277,7 +278,7 @@
 			from `tabPurchase Invoice Item` a
 			where a.item_code = %s and a.docstatus=1
 			and modified <= %s
-			order by a.modified desc limit 1""", (item_code,self.filters.to_date))
+			order by a.modified desc limit 1""", (item_code, self.filters.to_date))
 		else:
 			last_purchase_rate = frappe.db.sql("""
 			select (a.base_rate / a.conversion_factor)
diff --git a/erpnext/buying/doctype/purchase_order/purchase_order.js b/erpnext/buying/doctype/purchase_order/purchase_order.js
index ed054ae..4a8146a 100644
--- a/erpnext/buying/doctype/purchase_order/purchase_order.js
+++ b/erpnext/buying/doctype/purchase_order/purchase_order.js
@@ -27,15 +27,6 @@
 		frm.set_indicator_formatter('item_code',
 			function(doc) { return (doc.qty<=doc.received_qty) ? "green" : "orange" })
 
-		frm.set_query("blanket_order", "items", function() {
-			return {
-				filters: {
-					"company": frm.doc.company,
-					"docstatus": 1
-				}
-			}
-		});
-
 		frm.set_query("expense_account", "items", function() {
 			return {
 				query: "erpnext.controllers.queries.get_expense_account",
diff --git a/erpnext/controllers/queries.py b/erpnext/controllers/queries.py
index c14bb66..5febfd6 100644
--- a/erpnext/controllers/queries.py
+++ b/erpnext/controllers/queries.py
@@ -371,6 +371,19 @@
 		fields = ["name", "parent_account"],
 		limit_start=start, limit_page_length=page_len, as_list=True)
 
+def get_blanket_orders(doctype, txt, searchfield, start, page_len, filters):
+	return frappe.db.sql("""select distinct bo.name, bo.blanket_order_type, bo.to_date
+		from `tabBlanket Order` bo, `tabBlanket Order Item` boi
+		where
+			boi.parent = bo.name
+			and boi.item_code = {item_code}
+			and bo.blanket_order_type = '{blanket_order_type}'
+			and bo.company = {company}
+			and bo.docstatus = 1"""
+		.format(item_code = frappe.db.escape(filters.get("item")),
+			blanket_order_type = filters.get("blanket_order_type"),
+			company = frappe.db.escape(filters.get("company"))
+		))
 
 @frappe.whitelist()
 def get_income_account(doctype, txt, searchfield, start, page_len, filters):
diff --git a/erpnext/controllers/stock_controller.py b/erpnext/controllers/stock_controller.py
index 55a2c43..9d453af 100644
--- a/erpnext/controllers/stock_controller.py
+++ b/erpnext/controllers/stock_controller.py
@@ -3,7 +3,7 @@
 
 from __future__ import unicode_literals
 import frappe, erpnext
-from frappe.utils import cint, flt, cstr
+from frappe.utils import cint, flt, cstr, get_link_to_form, today, getdate
 from frappe import _
 import frappe.defaults
 from erpnext.accounts.utils import get_fiscal_year
@@ -55,6 +55,13 @@
 						frappe.throw(_("Row #{0}: Serial No {1} does not belong to Batch {2}")
 							.format(d.idx, serial_no_data.name, d.batch_no))
 
+			if d.qty > 0 and d.get("batch_no") and self.get("posting_date") and self.docstatus < 2:
+				expiry_date = frappe.get_cached_value("Batch", d.get("batch_no"), "expiry_date")
+
+				if expiry_date and getdate(expiry_date) < getdate(self.posting_date):
+					frappe.throw(_("Row #{0}: The batch {1} has already expired.")
+						.format(d.idx, get_link_to_form("Batch", d.get("batch_no"))))
+
 	def get_gl_entries(self, warehouse_account=None, default_expense_account=None,
 			default_cost_center=None):
 
diff --git a/erpnext/hr/doctype/expense_claim/expense_claim.js b/erpnext/hr/doctype/expense_claim/expense_claim.js
index 88f3865..fb23103 100644
--- a/erpnext/hr/doctype/expense_claim/expense_claim.js
+++ b/erpnext/hr/doctype/expense_claim/expense_claim.js
@@ -17,7 +17,7 @@
 			return;
 		}
 		return frappe.call({
-			method: "erpnext.hr.doctype.expense_claim.expense_claim.get_expense_claim_account",
+			method: "erpnext.hr.doctype.expense_claim.expense_claim.get_expense_claim_account_and_cost_center",
 			args: {
 				"expense_claim_type": d.expense_type,
 				"company": doc.company
@@ -25,6 +25,7 @@
 			callback: function(r) {
 				if (r.message) {
 					d.default_account = r.message.account;
+					d.cost_center = r.message.cost_center;
 				}
 			}
 		});
diff --git a/erpnext/hr/doctype/expense_claim/expense_claim.py b/erpnext/hr/doctype/expense_claim/expense_claim.py
index fe8afdf..ad9d86b 100644
--- a/erpnext/hr/doctype/expense_claim/expense_claim.py
+++ b/erpnext/hr/doctype/expense_claim/expense_claim.py
@@ -2,9 +2,9 @@
 # License: GNU General Public License v3. See license.txt
 
 from __future__ import unicode_literals
-import frappe
+import frappe, erpnext
 from frappe import _
-from frappe.utils import get_fullname, flt, cstr
+from frappe.utils import get_fullname, flt, cstr, get_link_to_form
 from frappe.model.document import Document
 from erpnext.hr.utils import set_employee_name
 from erpnext.accounts.party import get_party_account
@@ -192,7 +192,8 @@
 	def validate_account_details(self):
 		for data in self.expenses:
 			if not data.cost_center:
-				frappe.throw(_("Cost center is required to book an expense claim"))
+				frappe.throw(_("Row {0}: {1} is required in the expenses table to book an expense claim.")
+					.format(data.idx, frappe.bold("Cost Center")))
 
 		if self.is_paid:
 			if not self.mode_of_payment:
@@ -309,12 +310,22 @@
 	return je.as_dict()
 
 @frappe.whitelist()
+def get_expense_claim_account_and_cost_center(expense_claim_type, company):
+	data = get_expense_claim_account(expense_claim_type, company)
+	cost_center = erpnext.get_default_cost_center(company)
+
+	return {
+		"account": data.get("account"),
+		"cost_center": cost_center
+	}
+
+@frappe.whitelist()
 def get_expense_claim_account(expense_claim_type, company):
 	account = frappe.db.get_value("Expense Claim Account",
 		{"parent": expense_claim_type, "company": company}, "default_account")
 	if not account:
-		frappe.throw(_("Please set default account in Expense Claim Type {0}")
-			.format(expense_claim_type))
+		frappe.throw(_("Set the default account for the {0} {1}")
+			.format(frappe.bold("Expense Claim Type"), get_link_to_form("Expense Claim Type", expense_claim_type)))
 
 	return {
 		"account": account
diff --git a/erpnext/loan_management/doctype/loan_security/loan_security.json b/erpnext/loan_management/doctype/loan_security/loan_security.json
index e6984ee..e879b17 100644
--- a/erpnext/loan_management/doctype/loan_security/loan_security.json
+++ b/erpnext/loan_management/doctype/loan_security/loan_security.json
@@ -1,15 +1,17 @@
 {
+ "actions": [],
+ "allow_rename": 1,
  "autoname": "field:loan_security_name",
  "creation": "2019-09-02 15:07:08.885593",
  "doctype": "DocType",
  "editable_grid": 1,
  "engine": "InnoDB",
  "field_order": [
-  "loan_security_type",
-  "loan_security_code",
   "loan_security_name",
   "unit_of_measure",
+  "loan_security_code",
   "column_break_3",
+  "loan_security_type",
   "haircut",
   "disabled"
  ],
@@ -17,7 +19,9 @@
   {
    "fieldname": "loan_security_name",
    "fieldtype": "Data",
+   "in_list_view": 1,
    "label": "Loan Security Name",
+   "reqd": 1,
    "unique": 1
   },
   {
@@ -33,8 +37,10 @@
   {
    "fieldname": "loan_security_type",
    "fieldtype": "Link",
+   "in_list_view": 1,
    "label": "Loan Security Type",
-   "options": "Loan Security Type"
+   "options": "Loan Security Type",
+   "reqd": 1
   },
   {
    "fieldname": "loan_security_code",
@@ -52,11 +58,15 @@
    "fetch_from": "loan_security_type.unit_of_measure",
    "fieldname": "unit_of_measure",
    "fieldtype": "Link",
+   "in_list_view": 1,
    "label": "Unit Of Measure",
-   "options": "UOM"
+   "options": "UOM",
+   "read_only": 1,
+   "reqd": 1
   }
  ],
- "modified": "2019-11-16 11:36:37.901656",
+ "links": [],
+ "modified": "2020-04-28 14:07:54.506896",
  "modified_by": "Administrator",
  "module": "Loan Management",
  "name": "Loan Security",
@@ -87,7 +97,6 @@
    "write": 1
   }
  ],
- "quick_entry": 1,
  "search_fields": "loan_security_code",
  "sort_field": "modified",
  "sort_order": "DESC",
diff --git a/erpnext/loan_management/doctype/loan_security_type/loan_security_type.json b/erpnext/loan_management/doctype/loan_security_type/loan_security_type.json
index 5f29609..f46b88c 100644
--- a/erpnext/loan_management/doctype/loan_security_type/loan_security_type.json
+++ b/erpnext/loan_management/doctype/loan_security_type/loan_security_type.json
@@ -9,9 +9,9 @@
   "loan_security_type",
   "unit_of_measure",
   "haircut",
-  "disabled",
   "column_break_5",
-  "loan_to_value_ratio"
+  "loan_to_value_ratio",
+  "disabled"
  ],
  "fields": [
   {
@@ -23,7 +23,9 @@
   {
    "fieldname": "loan_security_type",
    "fieldtype": "Data",
+   "in_list_view": 1,
    "label": "Loan Security Type",
+   "reqd": 1,
    "unique": 1
   },
   {
@@ -34,8 +36,10 @@
   {
    "fieldname": "unit_of_measure",
    "fieldtype": "Link",
+   "in_list_view": 1,
    "label": "Unit Of Measure",
-   "options": "UOM"
+   "options": "UOM",
+   "reqd": 1
   },
   {
    "fieldname": "column_break_5",
@@ -48,7 +52,7 @@
   }
  ],
  "links": [],
- "modified": "2020-02-28 12:43:20.364447",
+ "modified": "2020-04-28 14:06:49.046177",
  "modified_by": "Administrator",
  "module": "Loan Management",
  "name": "Loan Security Type",
diff --git a/erpnext/public/js/controllers/transaction.js b/erpnext/public/js/controllers/transaction.js
index 5843034..c9d7728 100644
--- a/erpnext/public/js/controllers/transaction.js
+++ b/erpnext/public/js/controllers/transaction.js
@@ -175,6 +175,20 @@
 			};
 		}
 
+		if (this.frm.fields_dict["items"].grid.get_field('blanket_order')) {
+			this.frm.set_query("blanket_order", "items", function(doc, cdt, cdn) {
+				var item = locals[cdt][cdn];
+				return {
+					query: "erpnext.controllers.queries.get_blanket_orders",
+					filters: {
+						"company": doc.company,
+						"blanket_order_type": doc.doctype === "Sales Order" ? "Selling" : "Purchasing",
+						"item": item.item_code
+					}
+				}
+			});
+		}
+
 	},
 	onload: function() {
 		var me = this;
diff --git a/erpnext/selling/doctype/sales_order/sales_order.js b/erpnext/selling/doctype/sales_order/sales_order.js
index 3c1ffe9..45a43c5 100644
--- a/erpnext/selling/doctype/sales_order/sales_order.js
+++ b/erpnext/selling/doctype/sales_order/sales_order.js
@@ -65,15 +65,6 @@
 			}
 		});
 
-		frm.set_query("blanket_order", "items", function() {
-			return {
-				filters: {
-					"company": frm.doc.company,
-					"docstatus": 1
-				}
-			}
-		});
-
 		erpnext.queries.setup_warehouse_query(frm);
 	},
 
@@ -148,7 +139,7 @@
 					}
 
 					this.frm.add_custom_button(__('Pick List'), () => this.create_pick_list(), __('Create'));
-					
+
 					const order_is_a_sale = ["Sales", "Shopping Cart"].indexOf(doc.order_type) !== -1;
 					const order_is_maintenance = ["Maintenance"].indexOf(doc.order_type) !== -1;
 					// order type has been customised then show all the action buttons