Merge pull request #26170 from marination/web-item-group

fix: Website item group logic for product listing in Item Group pages
diff --git a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js
index f58c8f4..dc9094c 100644
--- a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js
+++ b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js
@@ -27,10 +27,6 @@
 		});
 	},
 
-	company: function() {
-		erpnext.accounts.dimensions.update_dimension(this.frm, this.frm.doctype);
-	},
-
 	onload: function() {
 		this._super();
 
@@ -569,5 +565,9 @@
 			frm: frm,
 			freeze_message: __("Creating Purchase Receipt ...")
 		})
-	}
+	},
+
+	company: function(frm) {
+		erpnext.accounts.dimensions.update_dimension(frm, frm.doctype);
+	},
 })
diff --git a/erpnext/crm/report/first_response_time_for_opportunity/first_response_time_for_opportunity.js b/erpnext/crm/report/first_response_time_for_opportunity/first_response_time_for_opportunity.js
index 3f5c95a..fe5707a 100644
--- a/erpnext/crm/report/first_response_time_for_opportunity/first_response_time_for_opportunity.js
+++ b/erpnext/crm/report/first_response_time_for_opportunity/first_response_time_for_opportunity.js
@@ -22,10 +22,10 @@
 	get_chart_data: function (_columns, result) {
 		return {
 			data: {
-				labels: result.map(d => d[0]),
+				labels: result.map(d => d.creation_date),
 				datasets: [{
 					name: "First Response Time",
-					values: result.map(d => d[1])
+					values: result.map(d => d.first_response_time)
 				}]
 			},
 			type: "line",
@@ -35,8 +35,7 @@
 						hide_days: 0,
 						hide_seconds: 0
 					};
-					value = frappe.utils.get_formatted_duration(d, duration_options);
-					return value;
+					return frappe.utils.get_formatted_duration(d, duration_options);
 				}
 			}
 		}
diff --git a/erpnext/hr/doctype/staffing_plan/staffing_plan.py b/erpnext/hr/doctype/staffing_plan/staffing_plan.py
index 533149a..e6c783a 100644
--- a/erpnext/hr/doctype/staffing_plan/staffing_plan.py
+++ b/erpnext/hr/doctype/staffing_plan/staffing_plan.py
@@ -41,7 +41,7 @@
 
 			detail.total_estimated_cost = 0
 			if detail.number_of_positions > 0:
-				if detail.vacancies > 0 and detail.estimated_cost_per_position:
+				if detail.vacancies and detail.estimated_cost_per_position:
 					detail.total_estimated_cost = cint(detail.vacancies) * flt(detail.estimated_cost_per_position)
 
 			self.total_estimated_budget += detail.total_estimated_cost
@@ -76,12 +76,12 @@
 		if cint(staffing_plan_detail.vacancies) > cint(parent_plan_details[0].vacancies) or \
 			flt(staffing_plan_detail.total_estimated_cost) > flt(parent_plan_details[0].total_estimated_cost):
 			frappe.throw(_("You can only plan for upto {0} vacancies and budget {1} \
-				for {2} as per staffing plan {3} for parent company {4}."
-				.format(cint(parent_plan_details[0].vacancies),
+				for {2} as per staffing plan {3} for parent company {4}.").format(
+					cint(parent_plan_details[0].vacancies),
 					parent_plan_details[0].total_estimated_cost,
 					frappe.bold(staffing_plan_detail.designation),
 					parent_plan_details[0].name,
-					parent_company)), ParentCompanyError)
+					parent_company), ParentCompanyError)
 
 		#Get vacanices already planned for all companies down the hierarchy of Parent Company
 		lft, rgt = frappe.get_cached_value('Company',  parent_company,  ["lft", "rgt"])
@@ -98,14 +98,14 @@
 			(flt(parent_plan_details[0].total_estimated_cost) < \
 			(flt(staffing_plan_detail.total_estimated_cost) + flt(all_sibling_details.total_estimated_cost))):
 			frappe.throw(_("{0} vacancies and {1} budget for {2} already planned for subsidiary companies of {3}. \
-				You can only plan for upto {4} vacancies and and budget {5} as per staffing plan {6} for parent company {3}."
-				.format(cint(all_sibling_details.vacancies),
+				You can only plan for upto {4} vacancies and and budget {5} as per staffing plan {6} for parent company {3}.").format(
+					cint(all_sibling_details.vacancies),
 					all_sibling_details.total_estimated_cost,
 					frappe.bold(staffing_plan_detail.designation),
 					parent_company,
 					cint(parent_plan_details[0].vacancies),
 					parent_plan_details[0].total_estimated_cost,
-					parent_plan_details[0].name)))
+					parent_plan_details[0].name))
 
 	def validate_with_subsidiary_plans(self, staffing_plan_detail):
 		#Valdate this plan with all child company plan
@@ -121,11 +121,11 @@
 			cint(staffing_plan_detail.vacancies) < cint(children_details.vacancies) or \
 			flt(staffing_plan_detail.total_estimated_cost) < flt(children_details.total_estimated_cost):
 			frappe.throw(_("Subsidiary companies have already planned for {1} vacancies at a budget of {2}. \
-				Staffing Plan for {0} should allocate more vacancies and budget for {3} than planned for its subsidiary companies"
-				.format(self.company,
+				Staffing Plan for {0} should allocate more vacancies and budget for {3} than planned for its subsidiary companies").format(
+					self.company,
 					cint(children_details.vacancies),
 					children_details.total_estimated_cost,
-					frappe.bold(staffing_plan_detail.designation))), SubsidiaryCompanyError)
+					frappe.bold(staffing_plan_detail.designation)), SubsidiaryCompanyError)
 
 @frappe.whitelist()
 def get_designation_counts(designation, company):
@@ -170,4 +170,4 @@
 				designation, from_date, to_date)
 
 	# Only a single staffing plan can be active for a designation on given date
-	return staffing_plan if staffing_plan else None
\ No newline at end of file
+	return staffing_plan if staffing_plan else None
diff --git a/erpnext/payroll/doctype/payroll_entry/payroll_entry.py b/erpnext/payroll/doctype/payroll_entry/payroll_entry.py
index 7a70679..e71d81f 100644
--- a/erpnext/payroll/doctype/payroll_entry/payroll_entry.py
+++ b/erpnext/payroll/doctype/payroll_entry/payroll_entry.py
@@ -11,6 +11,7 @@
 from erpnext.accounts.utils import get_fiscal_year
 from erpnext.hr.doctype.employee.employee import get_holiday_list_for_employee
 from frappe.desk.reportview import get_match_cond, get_filters_cond
+from erpnext.accounts.doctype.accounting_dimension.accounting_dimension import get_accounting_dimensions
 
 class PayrollEntry(Document):
 	def onload(self):
@@ -41,7 +42,7 @@
 				emp_with_sal_slip.append(employee_details.employee)
 
 		if len(emp_with_sal_slip):
-			frappe.throw(_("Salary Slip already exists for {0} ").format(comma_and(emp_with_sal_slip)))
+			frappe.throw(_("Salary Slip already exists for {0}").format(comma_and(emp_with_sal_slip)))
 
 	def on_cancel(self):
 		frappe.delete_doc("Salary Slip", frappe.db.sql_list("""select name from `tabSalary Slip`
@@ -211,7 +212,7 @@
 		return account_dict
 
 	def make_accrual_jv_entry(self):
-		self.check_permission('write')
+		self.check_permission("write")
 		earnings = self.get_salary_component_total(component_type = "earnings") or {}
 		deductions = self.get_salary_component_total(component_type = "deductions") or {}
 		payroll_payable_account = self.payroll_payable_account
@@ -219,12 +220,13 @@
 		precision = frappe.get_precision("Journal Entry Account", "debit_in_account_currency")
 
 		if earnings or deductions:
-			journal_entry = frappe.new_doc('Journal Entry')
-			journal_entry.voucher_type = 'Journal Entry'
-			journal_entry.user_remark = _('Accrual Journal Entry for salaries from {0} to {1}')\
+			journal_entry = frappe.new_doc("Journal Entry")
+			journal_entry.voucher_type = "Journal Entry"
+			journal_entry.user_remark = _("Accrual Journal Entry for salaries from {0} to {1}")\
 				.format(self.start_date, self.end_date)
 			journal_entry.company = self.company
 			journal_entry.posting_date = self.posting_date
+			accounting_dimensions = get_accounting_dimensions() or []
 
 			accounts = []
 			currencies = []
@@ -236,37 +238,34 @@
 			for acc_cc, amount in earnings.items():
 				exchange_rate, amt = self.get_amount_and_exchange_rate_for_journal_entry(acc_cc[0], amount, company_currency, currencies)
 				payable_amount += flt(amount, precision)
-				accounts.append({
+				accounts.append(self.update_accounting_dimensions({
 					"account": acc_cc[0],
 					"debit_in_account_currency": flt(amt, precision),
 					"exchange_rate": flt(exchange_rate),
-					"party_type": '',
 					"cost_center": acc_cc[1] or self.cost_center,
 					"project": self.project
-				})
+				}, accounting_dimensions))
 
 			# Deductions
 			for acc_cc, amount in deductions.items():
 				exchange_rate, amt = self.get_amount_and_exchange_rate_for_journal_entry(acc_cc[0], amount, company_currency, currencies)
 				payable_amount -= flt(amount, precision)
-				accounts.append({
+				accounts.append(self.update_accounting_dimensions({
 					"account": acc_cc[0],
 					"credit_in_account_currency": flt(amt, precision),
 					"exchange_rate": flt(exchange_rate),
 					"cost_center": acc_cc[1] or self.cost_center,
-					"party_type": '',
 					"project": self.project
-				})
+				}, accounting_dimensions))
 
 			# Payable amount
 			exchange_rate, payable_amt = self.get_amount_and_exchange_rate_for_journal_entry(payroll_payable_account, payable_amount, company_currency, currencies)
-			accounts.append({
+			accounts.append(self.update_accounting_dimensions({
 				"account": payroll_payable_account,
 				"credit_in_account_currency": flt(payable_amt, precision),
 				"exchange_rate": flt(exchange_rate),
-				"party_type": '',
 				"cost_center": self.cost_center
-			})
+			}, accounting_dimensions))
 
 			journal_entry.set("accounts", accounts)
 			if len(currencies) > 1:
@@ -286,6 +285,12 @@
 
 		return jv_name
 
+	def update_accounting_dimensions(self, row, accounting_dimensions):
+		for dimension in accounting_dimensions:
+			row.update({dimension: self.get(dimension)})
+
+		return row
+
 	def get_amount_and_exchange_rate_for_journal_entry(self, account, amount, company_currency, currencies):
 		conversion_rate = 1
 		exchange_rate = self.exchange_rate
diff --git a/erpnext/public/js/controllers/transaction.js b/erpnext/public/js/controllers/transaction.js
index 6dc40f0..b3af3d6 100644
--- a/erpnext/public/js/controllers/transaction.js
+++ b/erpnext/public/js/controllers/transaction.js
@@ -868,9 +868,6 @@
 
 		}
 
-		if (this.frm.doc.posting_date) var date = this.frm.doc.posting_date;
-		else var date = this.frm.doc.transaction_date;
-
 		if (frappe.meta.get_docfield(this.frm.doctype, "shipping_address") &&
 			in_list(['Purchase Order', 'Purchase Receipt', 'Purchase Invoice'], this.frm.doctype)) {
 			erpnext.utils.get_shipping_address(this.frm, function(){
diff --git a/erpnext/public/scss/shopping_cart.scss b/erpnext/public/scss/shopping_cart.scss
index 9402cf9..5962859 100644
--- a/erpnext/public/scss/shopping_cart.scss
+++ b/erpnext/public/scss/shopping_cart.scss
@@ -467,11 +467,15 @@
 
 	.btn-change-address {
 		color: var(--blue-500);
-		box-shadow: none;
-		border: 1px solid var(--blue-500);
 	}
 }
 
+.btn-new-address:hover, .btn-change-address:hover {
+	box-shadow: none;
+	color: var(--blue-500) !important;
+	border: 1px solid var(--blue-500);
+}
+
 .modal .address-card {
 	.card-body {
 		padding: var(--padding-sm);
diff --git a/erpnext/regional/report/gstr_1/gstr_1.py b/erpnext/regional/report/gstr_1/gstr_1.py
index 80e2d72..1096159 100644
--- a/erpnext/regional/report/gstr_1/gstr_1.py
+++ b/erpnext/regional/report/gstr_1/gstr_1.py
@@ -201,7 +201,7 @@
 		elif self.filters.get("type_of_business") ==  "EXPORT":
 			conditions += """ AND is_return !=1 and gst_category = 'Overseas' """
 
-		conditions += " AND billing_address_gstin NOT IN %(company_gstins)s"
+		conditions += " AND IFNULL(billing_address_gstin, '') NOT IN %(company_gstins)s"
 
 		return conditions
 
diff --git a/erpnext/selling/report/sales_order_analysis/sales_order_analysis.py b/erpnext/selling/report/sales_order_analysis/sales_order_analysis.py
index f5feb95..8cb2446 100644
--- a/erpnext/selling/report/sales_order_analysis/sales_order_analysis.py
+++ b/erpnext/selling/report/sales_order_analysis/sales_order_analysis.py
@@ -59,7 +59,7 @@
 			IF(so.status in ('Completed','To Bill'), 0, (SELECT delay_days)) as delay,
 			soi.qty, soi.delivered_qty,
 			(soi.qty - soi.delivered_qty) AS pending_qty,
-			IFNULL(sii.qty, 0) as billed_qty,
+			IFNULL(SUM(sii.qty), 0) as billed_qty,
 			soi.base_amount as amount,
 			(soi.delivered_qty * soi.base_rate) as delivered_qty_amount,
 			(soi.billed_amt * IFNULL(so.conversion_rate, 1)) as billed_amount,
diff --git a/erpnext/stock/report/incorrect_balance_qty_after_transaction/__init__.py b/erpnext/stock/report/incorrect_balance_qty_after_transaction/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/erpnext/stock/report/incorrect_balance_qty_after_transaction/__init__.py
diff --git a/erpnext/stock/report/incorrect_balance_qty_after_transaction/incorrect_balance_qty_after_transaction.js b/erpnext/stock/report/incorrect_balance_qty_after_transaction/incorrect_balance_qty_after_transaction.js
new file mode 100644
index 0000000..bf11277
--- /dev/null
+++ b/erpnext/stock/report/incorrect_balance_qty_after_transaction/incorrect_balance_qty_after_transaction.js
@@ -0,0 +1,27 @@
+// Copyright (c) 2016, Frappe Technologies Pvt. Ltd. and contributors
+// For license information, please see license.txt
+/* eslint-disable */
+
+frappe.query_reports["Incorrect Balance Qty After Transaction"] = {
+	"filters": [
+		{
+			label: __("Company"),
+			fieldtype: "Link",
+			fieldname: "company",
+			options: "Company",
+			default: frappe.defaults.get_user_default("Company"),
+			reqd: 1
+		},
+		{
+			label: __('Item Code'),
+			fieldtype: 'Link',
+			fieldname: 'item_code',
+			options: 'Item'
+		},
+		{
+			label: __('Warehouse'),
+			fieldtype: 'Link',
+			fieldname: 'warehouse'
+		}
+	]
+};
diff --git a/erpnext/stock/report/incorrect_balance_qty_after_transaction/incorrect_balance_qty_after_transaction.json b/erpnext/stock/report/incorrect_balance_qty_after_transaction/incorrect_balance_qty_after_transaction.json
new file mode 100644
index 0000000..a5815bc
--- /dev/null
+++ b/erpnext/stock/report/incorrect_balance_qty_after_transaction/incorrect_balance_qty_after_transaction.json
@@ -0,0 +1,32 @@
+{
+ "add_total_row": 0,
+ "columns": [],
+ "creation": "2021-05-12 16:47:58.717853",
+ "disable_prepared_report": 0,
+ "disabled": 0,
+ "docstatus": 0,
+ "doctype": "Report",
+ "filters": [],
+ "idx": 0,
+ "is_standard": "Yes",
+ "modified": "2021-05-12 16:48:28.347575",
+ "modified_by": "Administrator",
+ "module": "Stock",
+ "name": "Incorrect Balance Qty After Transaction",
+ "owner": "Administrator",
+ "prepared_report": 0,
+ "ref_doctype": "Stock Ledger Entry",
+ "report_name": "Incorrect Balance Qty After Transaction",
+ "report_type": "Script Report",
+ "roles": [
+  {
+   "role": "Stock User"
+  },
+  {
+   "role": "Stock Manager"
+  },
+  {
+   "role": "Purchase User"
+  }
+ ]
+}
\ No newline at end of file
diff --git a/erpnext/stock/report/incorrect_balance_qty_after_transaction/incorrect_balance_qty_after_transaction.py b/erpnext/stock/report/incorrect_balance_qty_after_transaction/incorrect_balance_qty_after_transaction.py
new file mode 100644
index 0000000..cf174c9
--- /dev/null
+++ b/erpnext/stock/report/incorrect_balance_qty_after_transaction/incorrect_balance_qty_after_transaction.py
@@ -0,0 +1,111 @@
+# Copyright (c) 2013, Frappe Technologies Pvt. Ltd. and contributors
+# For license information, please see license.txt
+
+import frappe
+from frappe import _
+from six import iteritems
+from frappe.utils import flt
+
+def execute(filters=None):
+	columns, data = [], []
+	columns = get_columns()
+	data = get_data(filters)
+	return columns, data
+
+def get_data(filters):
+	data = get_stock_ledger_entries(filters)
+	itewise_balance_qty = {}
+
+	for row in data:
+		key = (row.item_code, row.warehouse)
+		itewise_balance_qty.setdefault(key, []).append(row)
+
+	res = validate_data(itewise_balance_qty)
+	return res
+
+def validate_data(itewise_balance_qty):
+	res = []
+	for key, data in iteritems(itewise_balance_qty):
+		row = get_incorrect_data(data)
+		if row:
+			res.append(row)
+			res.append({})
+
+	return res
+
+def get_incorrect_data(data):
+	balance_qty = 0.0
+	for row in data:
+		balance_qty += row.actual_qty
+		if row.voucher_type == "Stock Reconciliation" and not row.batch_no:
+			balance_qty = flt(row.qty_after_transaction)
+
+		row.expected_balance_qty = balance_qty
+		if abs(flt(row.expected_balance_qty) - flt(row.qty_after_transaction)) > 0.5:
+			row.differnce = abs(flt(row.expected_balance_qty) - flt(row.qty_after_transaction))
+			return row
+
+def get_stock_ledger_entries(report_filters):
+	filters = {}
+	fields = ['name', 'voucher_type', 'voucher_no', 'item_code', 'actual_qty',
+		'posting_date', 'posting_time', 'company', 'warehouse', 'qty_after_transaction', 'batch_no']
+
+	for field in ['warehouse', 'item_code', 'company']:
+		if report_filters.get(field):
+			filters[field] = report_filters.get(field)
+
+	return frappe.get_all('Stock Ledger Entry', fields = fields, filters = filters,
+		order_by = 'timestamp(posting_date, posting_time) asc, creation asc')
+
+def get_columns():
+	return [{
+		'label': _('Id'),
+		'fieldtype': 'Link',
+		'fieldname': 'name',
+		'options': 'Stock Ledger Entry',
+		'width': 120
+	}, {
+		'label': _('Posting Date'),
+		'fieldtype': 'Date',
+		'fieldname': 'posting_date',
+		'width': 110
+	}, {
+		'label': _('Voucher Type'),
+		'fieldtype': 'Link',
+		'fieldname': 'voucher_type',
+		'options': 'DocType',
+		'width': 120
+	}, {
+		'label': _('Voucher No'),
+		'fieldtype': 'Dynamic Link',
+		'fieldname': 'voucher_no',
+		'options': 'voucher_type',
+		'width': 120
+	}, {
+		'label': _('Item Code'),
+		'fieldtype': 'Link',
+		'fieldname': 'item_code',
+		'options': 'Item',
+		'width': 120
+	}, {
+		'label': _('Warehouse'),
+		'fieldtype': 'Link',
+		'fieldname': 'warehouse',
+		'options': 'Warehouse',
+		'width': 120
+	}, {
+		'label': _('Expected Balance Qty'),
+		'fieldtype': 'Float',
+		'fieldname': 'expected_balance_qty',
+		'width': 170
+	}, {
+		'label': _('Actual Balance Qty'),
+		'fieldtype': 'Float',
+		'fieldname': 'qty_after_transaction',
+		'width': 150
+	}, {
+		'label': _('Difference'),
+		'fieldtype': 'Float',
+		'fieldname': 'differnce',
+		'width': 110
+	}]
\ No newline at end of file
diff --git a/erpnext/stock/report/incorrect_serial_no_valuation/__init__.py b/erpnext/stock/report/incorrect_serial_no_valuation/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/erpnext/stock/report/incorrect_serial_no_valuation/__init__.py
diff --git a/erpnext/stock/report/incorrect_serial_no_valuation/incorrect_serial_no_valuation.js b/erpnext/stock/report/incorrect_serial_no_valuation/incorrect_serial_no_valuation.js
new file mode 100644
index 0000000..c62d480
--- /dev/null
+++ b/erpnext/stock/report/incorrect_serial_no_valuation/incorrect_serial_no_valuation.js
@@ -0,0 +1,35 @@
+// Copyright (c) 2016, Frappe Technologies Pvt. Ltd. and contributors
+// For license information, please see license.txt
+/* eslint-disable */
+
+frappe.query_reports["Incorrect Serial No Valuation"] = {
+	"filters": [
+		{
+			label: __('Item Code'),
+			fieldtype: 'Link',
+			fieldname: 'item_code',
+			options: 'Item',
+			get_query: function() {
+				return {
+					filters: {
+						'has_serial_no': 1
+					}
+				}
+			}
+		},
+		{
+			label: __('From Date'),
+			fieldtype: 'Date',
+			fieldname: 'from_date',
+			reqd: 1,
+			default: frappe.defaults.get_user_default("year_start_date")
+		},
+		{
+			label: __('To Date'),
+			fieldtype: 'Date',
+			fieldname: 'to_date',
+			reqd: 1,
+			default: frappe.defaults.get_user_default("year_end_date")
+		}
+	]
+};
diff --git a/erpnext/stock/report/incorrect_serial_no_valuation/incorrect_serial_no_valuation.json b/erpnext/stock/report/incorrect_serial_no_valuation/incorrect_serial_no_valuation.json
new file mode 100644
index 0000000..cc384a5
--- /dev/null
+++ b/erpnext/stock/report/incorrect_serial_no_valuation/incorrect_serial_no_valuation.json
@@ -0,0 +1,36 @@
+{
+ "add_total_row": 0,
+ "columns": [],
+ "creation": "2021-05-13 13:07:00.767845",
+ "disable_prepared_report": 0,
+ "disabled": 0,
+ "docstatus": 0,
+ "doctype": "Report",
+ "filters": [],
+ "idx": 0,
+ "is_standard": "Yes",
+ "json": "{}",
+ "modified": "2021-05-13 13:07:00.767845",
+ "modified_by": "Administrator",
+ "module": "Stock",
+ "name": "Incorrect Serial No Valuation",
+ "owner": "Administrator",
+ "prepared_report": 0,
+ "ref_doctype": "Stock Ledger Entry",
+ "report_name": "Incorrect Serial No Valuation",
+ "report_type": "Script Report",
+ "roles": [
+  {
+   "role": "Stock User"
+  },
+  {
+   "role": "Accounts Manager"
+  },
+  {
+   "role": "Accounts User"
+  },
+  {
+   "role": "Stock Manager"
+  }
+ ]
+}
\ No newline at end of file
diff --git a/erpnext/stock/report/incorrect_serial_no_valuation/incorrect_serial_no_valuation.py b/erpnext/stock/report/incorrect_serial_no_valuation/incorrect_serial_no_valuation.py
new file mode 100644
index 0000000..e54cf4c
--- /dev/null
+++ b/erpnext/stock/report/incorrect_serial_no_valuation/incorrect_serial_no_valuation.py
@@ -0,0 +1,148 @@
+# Copyright (c) 2013, Frappe Technologies Pvt. Ltd. and contributors
+# For license information, please see license.txt
+
+import frappe
+import copy
+from frappe import _
+from six import iteritems
+from erpnext.stock.doctype.serial_no.serial_no import get_serial_nos
+
+def execute(filters=None):
+	columns, data = [], []
+	columns = get_columns()
+	data = get_data(filters)
+	return columns, data
+
+def get_data(filters):
+	data = get_stock_ledger_entries(filters)
+	serial_nos_data = prepare_serial_nos(data)
+	data = get_incorrect_serial_nos(serial_nos_data)
+
+	return data
+
+def prepare_serial_nos(data):
+	serial_no_wise_data = {}
+	for row in data:
+		if not row.serial_nos:
+			continue
+
+		for serial_no in get_serial_nos(row.serial_nos):
+			sle = copy.deepcopy(row)
+			sle.serial_no = serial_no
+			sle.qty = 1 if sle.actual_qty > 0 else -1
+			sle.valuation_rate = sle.valuation_rate if sle.actual_qty > 0 else sle.valuation_rate * -1
+			serial_no_wise_data.setdefault(serial_no, []).append(sle)
+
+	return serial_no_wise_data
+
+def get_incorrect_serial_nos(serial_nos_data):
+	result = []
+
+	total_value = frappe._dict({'qty': 0, 'valuation_rate': 0, 'serial_no': frappe.bold(_('Balance'))})
+
+	for serial_no, data in iteritems(serial_nos_data):
+		total_dict = frappe._dict({'qty': 0, 'valuation_rate': 0, 'serial_no': frappe.bold(_('Total'))})
+
+		if check_incorrect_serial_data(data, total_dict):
+			result.extend(data)
+
+			total_value.qty += total_dict.qty
+			total_value.valuation_rate += total_dict.valuation_rate
+
+			result.append(total_dict)
+			result.append({})
+
+	result.append(total_value)
+
+	return result
+
+def check_incorrect_serial_data(data, total_dict):
+	incorrect_data = False
+	for row in data:
+		total_dict.qty += row.qty
+		total_dict.valuation_rate += row.valuation_rate
+
+		if ((total_dict.qty == 0 and abs(total_dict.valuation_rate) > 0) or total_dict.qty < 0):
+			incorrect_data = True
+
+	return incorrect_data
+
+def get_stock_ledger_entries(report_filters):
+	fields = ['name', 'voucher_type', 'voucher_no', 'item_code', 'serial_no as serial_nos', 'actual_qty',
+		'posting_date', 'posting_time', 'company', 'warehouse', '(stock_value_difference / actual_qty) as valuation_rate']
+
+	filters = {'serial_no': ("is", "set")}
+
+	if report_filters.get('item_code'):
+		filters['item_code'] = report_filters.get('item_code')
+
+	if report_filters.get('from_date') and report_filters.get('to_date'):
+		filters['posting_date'] = ('between', [report_filters.get('from_date'), report_filters.get('to_date')])
+
+	return frappe.get_all('Stock Ledger Entry', fields = fields, filters = filters,
+		order_by = 'timestamp(posting_date, posting_time) asc, creation asc')
+
+def get_columns():
+	return [{
+		'label': _('Company'),
+		'fieldtype': 'Link',
+		'fieldname': 'company',
+		'options': 'Company',
+		'width': 120
+	}, {
+		'label': _('Id'),
+		'fieldtype': 'Link',
+		'fieldname': 'name',
+		'options': 'Stock Ledger Entry',
+		'width': 120
+	}, {
+		'label': _('Posting Date'),
+		'fieldtype': 'Date',
+		'fieldname': 'posting_date',
+		'width': 90
+	}, {
+		'label': _('Posting Time'),
+		'fieldtype': 'Time',
+		'fieldname': 'posting_time',
+		'width': 90
+	}, {
+		'label': _('Voucher Type'),
+		'fieldtype': 'Link',
+		'fieldname': 'voucher_type',
+		'options': 'DocType',
+		'width': 100
+	}, {
+		'label': _('Voucher No'),
+		'fieldtype': 'Dynamic Link',
+		'fieldname': 'voucher_no',
+		'options': 'voucher_type',
+		'width': 110
+	}, {
+		'label': _('Item Code'),
+		'fieldtype': 'Link',
+		'fieldname': 'item_code',
+		'options': 'Item',
+		'width': 120
+	}, {
+		'label': _('Warehouse'),
+		'fieldtype': 'Link',
+		'fieldname': 'warehouse',
+		'options': 'Warehouse',
+		'width': 120
+	}, {
+		'label': _('Serial No'),
+		'fieldtype': 'Link',
+		'fieldname': 'serial_no',
+		'options': 'Serial No',
+		'width': 100
+	}, {
+		'label': _('Qty'),
+		'fieldtype': 'Float',
+		'fieldname': 'qty',
+		'width': 80
+	}, {
+		'label': _('Valuation Rate (In / Out)'),
+		'fieldtype': 'Currency',
+		'fieldname': 'valuation_rate',
+		'width': 110
+	}]
\ No newline at end of file
diff --git a/erpnext/stock/workspace/stock/stock.json b/erpnext/stock/workspace/stock/stock.json
index 3221dc4..529ce8e 100644
--- a/erpnext/stock/workspace/stock/stock.json
+++ b/erpnext/stock/workspace/stock/stock.json
@@ -15,6 +15,7 @@
  "hide_custom": 0,
  "icon": "stock",
  "idx": 0,
+ "is_default": 0,
  "is_standard": 1,
  "label": "Stock",
  "links": [
@@ -653,9 +654,44 @@
    "link_type": "Report",
    "onboard": 0,
    "type": "Link"
+  },
+  {
+   "hidden": 0,
+   "is_query_report": 0,
+   "label": "Incorrect Data Report",
+   "link_type": "DocType",
+   "onboard": 0,
+   "type": "Card Break"
+  },
+  {
+   "hidden": 0,
+   "is_query_report": 0,
+   "label": "Incorrect Serial No Qty and Valuation",
+   "link_to": "Incorrect Serial No Valuation",
+   "link_type": "Report",
+   "onboard": 0,
+   "type": "Link"
+  },
+  {
+   "hidden": 0,
+   "is_query_report": 0,
+   "label": "Incorrect Balance Qty After Transaction",
+   "link_to": "Incorrect Balance Qty After Transaction",
+   "link_type": "Report",
+   "onboard": 0,
+   "type": "Link"
+  },
+  {
+   "hidden": 0,
+   "is_query_report": 0,
+   "label": "Stock and Account Value Comparison",
+   "link_to": "Stock and Account Value Comparison",
+   "link_type": "Report",
+   "onboard": 0,
+   "type": "Link"
   }
  ],
- "modified": "2020-12-01 13:38:36.282890",
+ "modified": "2021-05-13 13:10:24.914983",
  "modified_by": "Administrator",
  "module": "Stock",
  "name": "Stock",
diff --git a/erpnext/support/report/first_response_time_for_issues/first_response_time_for_issues.js b/erpnext/support/report/first_response_time_for_issues/first_response_time_for_issues.js
index 576e0b7..18691fe 100644
--- a/erpnext/support/report/first_response_time_for_issues/first_response_time_for_issues.js
+++ b/erpnext/support/report/first_response_time_for_issues/first_response_time_for_issues.js
@@ -22,10 +22,10 @@
 	get_chart_data: function(_columns, result) {
 		return {
 			data: {
-				labels: result.map(d => d[0]),
+				labels: result.map(d => d.creation_date),
 				datasets: [{
 					name: 'First Response Time',
-					values: result.map(d => d[1])
+					values: result.map(d => d.first_response_time)
 				}]
 			},
 			type: "line",
@@ -35,8 +35,7 @@
 						hide_days: 0,
 						hide_seconds: 0
 					};
-					value = frappe.utils.get_formatted_duration(d, duration_options);
-					return value;
+					return frappe.utils.get_formatted_duration(d, duration_options);
 				}
 			}
 		}
diff --git a/erpnext/templates/includes/cart/cart_address.html b/erpnext/templates/includes/cart/cart_address.html
index 84a9430..4482bc1 100644
--- a/erpnext/templates/includes/cart/cart_address.html
+++ b/erpnext/templates/includes/cart/cart_address.html
@@ -99,6 +99,7 @@
 					fieldname: 'country',
 					fieldtype: 'Link',
 					options: 'Country',
+					only_select: true,
 					reqd: 1
 				},
 				{