Merge branch 'develop' of https://github.com/frappe/erpnext into mergify/bp/develop/pr-28935
diff --git a/.github/ISSUE_TEMPLATE/bug_report.yaml b/.github/ISSUE_TEMPLATE/bug_report.yaml
index a6e16a0..8f93811 100644
--- a/.github/ISSUE_TEMPLATE/bug_report.yaml
+++ b/.github/ISSUE_TEMPLATE/bug_report.yaml
@@ -25,20 +25,6 @@
       required: true
 
   - type: dropdown
-    id: version
-    attributes:
-      label: Version
-      description: Affected versions.
-      multiple: true
-      options:
-        - v12
-        - v13
-        - v14
-        - develop
-    validations:
-      required: true
-
-  - type: dropdown
     id: module
     attributes:
       label: Module
@@ -86,7 +72,7 @@
         - manual install
         - FrappeCloud
     validations:
-      required: true
+      required: false
 
   - type: textarea
     id: logs
@@ -95,12 +81,7 @@
       description: Please copy and paste any relevant log output. This will be automatically formatted.
       render: shell
 
-
-  - type: checkboxes
-    id: terms
+  - type: markdown
     attributes:
-      label: Code of Conduct
-      description: By submitting this issue, you agree to follow our [Code of Conduct](https://github.com/frappe/erpnext/blob/develop/CODE_OF_CONDUCT.md)
-      options:
-        - label: I agree to follow this project's Code of Conduct
-          required: true
+      value: |
+        By submitting this issue, you agree to follow our [Code of Conduct](https://github.com/frappe/erpnext/blob/develop/CODE_OF_CONDUCT.md)
diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py
index 64712b5..321b453 100644
--- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py
+++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py
@@ -1049,6 +1049,8 @@
 					frappe.flags.is_reverse_depr_entry = False
 					asset.flags.ignore_validate_update_after_submit = True
 					schedule.journal_entry = None
+					depreciation_amount = self.get_depreciation_amount_in_je(reverse_journal_entry)
+					asset.finance_books[0].value_after_depreciation += depreciation_amount
 					asset.save()
 
 	def get_posting_date_of_sales_invoice(self):
@@ -1071,6 +1073,12 @@
 
 		return False
 
+	def get_depreciation_amount_in_je(self, journal_entry):
+		if journal_entry.accounts[0].debit_in_account_currency:
+			return journal_entry.accounts[0].debit_in_account_currency
+		else:
+			return journal_entry.accounts[0].credit_in_account_currency
+
 	@property
 	def enable_discount_accounting(self):
 		if not hasattr(self, "_enable_discount_accounting"):
diff --git a/erpnext/crm/doctype/lead/test_lead.py b/erpnext/crm/doctype/lead/test_lead.py
index 56bfc8f..3882974 100644
--- a/erpnext/crm/doctype/lead/test_lead.py
+++ b/erpnext/crm/doctype/lead/test_lead.py
@@ -23,6 +23,17 @@
 		customer.customer_group = "_Test Customer Group"
 		customer.insert()
 
+		#check whether lead contact is carried forward to the customer.
+		contact = frappe.db.get_value('Dynamic Link', {
+			"parenttype": "Contact",
+			"link_doctype": "Lead",
+			"link_name": customer.lead_name,
+		}, "parent")
+
+		if contact:
+			contact_doc = frappe.get_doc("Contact", contact)
+			self.assertEqual(contact_doc.has_link(customer.doctype, customer.name), True)
+
 	def test_make_customer_from_organization(self):
 		from erpnext.crm.doctype.lead.lead import make_customer
 
diff --git a/erpnext/erpnext_integrations/workspace/erpnext_integrations_settings/erpnext_integrations_settings.json b/erpnext/erpnext_integrations/workspace/erpnext_integrations_settings/erpnext_integrations_settings.json
deleted file mode 100644
index 5efafd6..0000000
--- a/erpnext/erpnext_integrations/workspace/erpnext_integrations_settings/erpnext_integrations_settings.json
+++ /dev/null
@@ -1,78 +0,0 @@
-{
- "charts": [],
- "content": "[{\"type\": \"header\", \"data\": {\"text\": \"Reports & Masters\", \"level\": 4, \"col\": 12}}, {\"type\": \"card\", \"data\": {\"card_name\": \"Integrations Settings\", \"col\": 4}}]",
- "creation": "2020-07-31 10:38:54.021237",
- "docstatus": 0,
- "doctype": "Workspace",
- "for_user": "",
- "hide_custom": 0,
- "icon": "setting",
- "idx": 0,
- "label": "ERPNext Integrations Settings",
- "links": [
-  {
-   "hidden": 0,
-   "is_query_report": 0,
-   "label": "Integrations Settings",
-   "link_count": 0,
-   "onboard": 0,
-   "type": "Card Break"
-  },
-  {
-   "dependencies": "",
-   "hidden": 0,
-   "is_query_report": 0,
-   "label": "Woocommerce Settings",
-   "link_count": 0,
-   "link_to": "Woocommerce Settings",
-   "link_type": "DocType",
-   "onboard": 0,
-   "type": "Link"
-  },
-  {
-   "dependencies": "",
-   "hidden": 0,
-   "is_query_report": 0,
-   "label": "Amazon MWS Settings",
-   "link_count": 0,
-   "link_to": "Amazon MWS Settings",
-   "link_type": "DocType",
-   "onboard": 0,
-   "type": "Link"
-  },
-  {
-   "dependencies": "",
-   "hidden": 0,
-   "is_query_report": 0,
-   "label": "Plaid Settings",
-   "link_count": 0,
-   "link_to": "Plaid Settings",
-   "link_type": "DocType",
-   "onboard": 0,
-   "type": "Link"
-  },
-  {
-   "dependencies": "",
-   "hidden": 0,
-   "is_query_report": 0,
-   "label": "Exotel Settings",
-   "link_count": 0,
-   "link_to": "Exotel Settings",
-   "link_type": "DocType",
-   "onboard": 0,
-   "type": "Link"
-  }
- ],
- "modified": "2021-11-23 04:30:33.106991",
- "modified_by": "Administrator",
- "module": "ERPNext Integrations",
- "name": "ERPNext Integrations Settings",
- "owner": "Administrator",
- "parent_page": "",
- "public": 1,
- "restrict_to_domain": "",
- "roles": [],
- "sequence_id": 11,
- "shortcuts": [],
- "title": "ERPNext Integrations Settings"
-}
\ No newline at end of file
diff --git a/erpnext/hooks.py b/erpnext/hooks.py
index 9ceb626..1d11f20 100644
--- a/erpnext/hooks.py
+++ b/erpnext/hooks.py
@@ -374,7 +374,7 @@
 		"erpnext.selling.doctype.quotation.quotation.set_expired_status",
 		"erpnext.buying.doctype.supplier_quotation.supplier_quotation.set_expired_status",
 		"erpnext.accounts.doctype.process_statement_of_accounts.process_statement_of_accounts.send_auto_email",
-		"erpnext.non_profit.doctype.membership.membership.set_expired_status"
+		"erpnext.non_profit.doctype.membership.membership.set_expired_status",
 		"erpnext.hr.doctype.interview.interview.send_daily_feedback_reminder"
 	],
 	"daily_long": [
diff --git a/erpnext/hr/doctype/leave_allocation/test_leave_allocation.py b/erpnext/hr/doctype/leave_allocation/test_leave_allocation.py
index 46401a2..6dbe2ec 100644
--- a/erpnext/hr/doctype/leave_allocation/test_leave_allocation.py
+++ b/erpnext/hr/doctype/leave_allocation/test_leave_allocation.py
@@ -4,6 +4,7 @@
 from frappe.utils import add_days, add_months, getdate, nowdate
 
 import erpnext
+from erpnext.hr.doctype.employee.test_employee import make_employee
 from erpnext.hr.doctype.leave_ledger_entry.leave_ledger_entry import process_expired_allocation
 from erpnext.hr.doctype.leave_type.test_leave_type import create_leave_type
 
@@ -11,18 +12,25 @@
 class TestLeaveAllocation(unittest.TestCase):
 	@classmethod
 	def setUpClass(cls):
+		from erpnext.payroll.doctype.salary_slip.test_salary_slip import make_holiday_list
+
 		frappe.db.sql("delete from `tabLeave Period`")
+		emp_id = make_employee("test_emp_leave_allocation@salary.com")
+		cls.employee = frappe.get_doc("Employee", emp_id)
+
+		make_holiday_list()
+		frappe.db.set_value("Company", erpnext.get_default_company(), "default_holiday_list", "Salary Slip Test Holiday List")
+
+	def tearDown(self):
+		frappe.db.rollback()
 
 	def test_overlapping_allocation(self):
-		frappe.db.sql("delete from `tabLeave Allocation`")
-
-		employee = frappe.get_doc("Employee", frappe.db.sql_list("select name from tabEmployee limit 1")[0])
 		leaves = [
 			{
 				"doctype": "Leave Allocation",
 				"__islocal": 1,
-				"employee": employee.name,
-				"employee_name": employee.employee_name,
+				"employee": self.employee.name,
+				"employee_name": self.employee.employee_name,
 				"leave_type": "_Test Leave Type",
 				"from_date": getdate("2015-10-01"),
 				"to_date": getdate("2015-10-31"),
@@ -32,8 +40,8 @@
 			{
 				"doctype": "Leave Allocation",
 				"__islocal": 1,
-				"employee": employee.name,
-				"employee_name": employee.employee_name,
+				"employee": self.employee.name,
+				"employee_name": self.employee.employee_name,
 				"leave_type": "_Test Leave Type",
 				"from_date": getdate("2015-09-01"),
 				"to_date": getdate("2015-11-30"),
@@ -45,40 +53,36 @@
 		self.assertRaises(frappe.ValidationError, frappe.get_doc(leaves[1]).save)
 
 	def test_invalid_period(self):
-		employee = frappe.get_doc("Employee", frappe.db.sql_list("select name from tabEmployee limit 1")[0])
-
 		doc = frappe.get_doc({
 			"doctype": "Leave Allocation",
 			"__islocal": 1,
-			"employee": employee.name,
-			"employee_name": employee.employee_name,
+			"employee": self.employee.name,
+			"employee_name": self.employee.employee_name,
 			"leave_type": "_Test Leave Type",
 			"from_date": getdate("2015-09-30"),
 			"to_date": getdate("2015-09-1"),
 			"new_leaves_allocated": 5
 		})
 
-		#invalid period
+		# invalid period
 		self.assertRaises(frappe.ValidationError, doc.save)
 
 	def test_allocated_leave_days_over_period(self):
-		employee = frappe.get_doc("Employee", frappe.db.sql_list("select name from tabEmployee limit 1")[0])
 		doc = frappe.get_doc({
 			"doctype": "Leave Allocation",
 			"__islocal": 1,
-			"employee": employee.name,
-			"employee_name": employee.employee_name,
+			"employee": self.employee.name,
+			"employee_name": self.employee.employee_name,
 			"leave_type": "_Test Leave Type",
 			"from_date": getdate("2015-09-1"),
 			"to_date": getdate("2015-09-30"),
 			"new_leaves_allocated": 35
 		})
-		#allocated leave more than period
+
+		# allocated leave more than period
 		self.assertRaises(frappe.ValidationError, doc.save)
 
 	def test_carry_forward_calculation(self):
-		frappe.db.sql("delete from `tabLeave Allocation`")
-		frappe.db.sql("delete from `tabLeave Ledger Entry`")
 		leave_type = create_leave_type(leave_type_name="_Test_CF_leave", is_carry_forward=1)
 		leave_type.maximum_carry_forwarded_leaves = 10
 		leave_type.max_leaves_allowed = 30
@@ -114,8 +118,6 @@
 		self.assertEqual(leave_allocation_2.unused_leaves, 5)
 
 	def test_carry_forward_leaves_expiry(self):
-		frappe.db.sql("delete from `tabLeave Allocation`")
-		frappe.db.sql("delete from `tabLeave Ledger Entry`")
 		leave_type = create_leave_type(
 			leave_type_name="_Test_CF_leave_expiry",
 			is_carry_forward=1,
@@ -151,8 +153,6 @@
 		self.assertEqual(leave_allocation_1.unused_leaves, leave_allocation.new_leaves_allocated)
 
 	def test_creation_of_leave_ledger_entry_on_submit(self):
-		frappe.db.sql("delete from `tabLeave Allocation`")
-
 		leave_allocation = create_leave_allocation()
 		leave_allocation.submit()
 
@@ -168,9 +168,6 @@
 		self.assertFalse(frappe.db.exists("Leave Ledger Entry", {'transaction_name':leave_allocation.name}))
 
 	def test_leave_addition_after_submit(self):
-		frappe.db.sql("delete from `tabLeave Allocation`")
-		frappe.db.sql("delete from `tabLeave Ledger Entry`")
-
 		leave_allocation = create_leave_allocation()
 		leave_allocation.submit()
 		self.assertTrue(leave_allocation.total_leaves_allocated, 15)
@@ -179,8 +176,6 @@
 		self.assertTrue(leave_allocation.total_leaves_allocated, 40)
 
 	def test_leave_subtraction_after_submit(self):
-		frappe.db.sql("delete from `tabLeave Allocation`")
-		frappe.db.sql("delete from `tabLeave Ledger Entry`")
 		leave_allocation = create_leave_allocation()
 		leave_allocation.submit()
 		self.assertTrue(leave_allocation.total_leaves_allocated, 15)
@@ -188,17 +183,14 @@
 		leave_allocation.submit()
 		self.assertTrue(leave_allocation.total_leaves_allocated, 10)
 
-	def test_against_leave_application_validation_after_submit(self):
-		frappe.db.sql("delete from `tabLeave Allocation`")
-		frappe.db.sql("delete from `tabLeave Ledger Entry`")
-
+	def test_validation_against_leave_application_after_submit(self):
 		leave_allocation = create_leave_allocation()
 		leave_allocation.submit()
 		self.assertTrue(leave_allocation.total_leaves_allocated, 15)
-		employee = frappe.get_doc("Employee", frappe.db.sql_list("select name from tabEmployee limit 1")[0])
+
 		leave_application = frappe.get_doc({
 			"doctype": 'Leave Application',
-			"employee": employee.name,
+			"employee": self.employee.name,
 			"leave_type": "_Test Leave Type",
 			"from_date": add_months(nowdate(), 2),
 			"to_date": add_months(add_days(nowdate(), 10), 2),
@@ -208,15 +200,20 @@
 			"leave_approver": 'test@example.com'
 		})
 		leave_application.submit()
-		leave_allocation.new_leaves_allocated = 8
-		leave_allocation.total_leaves_allocated = 8
+		leave_application.reload()
+
+		# allocate less leaves than the ones which are already approved
+		leave_allocation.new_leaves_allocated = leave_application.total_leave_days - 1
+		leave_allocation.total_leaves_allocated = leave_application.total_leave_days - 1
 		self.assertRaises(frappe.ValidationError, leave_allocation.submit)
 
 def create_leave_allocation(**args):
 	args = frappe._dict(args)
 
-	employee = frappe.get_doc("Employee", frappe.db.sql_list("select name from tabEmployee limit 1")[0])
-	leave_allocation = frappe.get_doc({
+	emp_id = make_employee("test_emp_leave_allocation@salary.com")
+	employee = frappe.get_doc("Employee", emp_id)
+
+	return frappe.get_doc({
 		"doctype": "Leave Allocation",
 		"__islocal": 1,
 		"employee": args.employee or employee.name,
@@ -227,6 +224,5 @@
 		"carry_forward": args.carry_forward or 0,
 		"to_date": args.to_date or add_months(nowdate(), 12)
 	})
-	return leave_allocation
 
 test_dependencies = ["Employee", "Leave Type"]
diff --git a/erpnext/patches.txt b/erpnext/patches.txt
index 47be130..716dcc0 100644
--- a/erpnext/patches.txt
+++ b/erpnext/patches.txt
@@ -319,4 +319,4 @@
 erpnext.patches.v13_0.disable_ksa_print_format_for_others # 16-12-2021
 erpnext.patches.v14_0.add_default_exit_questionnaire_notification_template
 erpnext.patches.v13_0.update_tax_category_for_rcm
-
+execute:frappe.delete_doc_if_exists('Workspace', 'ERPNext Integrations Settings')
diff --git a/erpnext/patches/v11_0/add_default_dispatch_notification_template.py b/erpnext/patches/v11_0/add_default_dispatch_notification_template.py
index 08006ad..c7771a5 100644
--- a/erpnext/patches/v11_0/add_default_dispatch_notification_template.py
+++ b/erpnext/patches/v11_0/add_default_dispatch_notification_template.py
@@ -22,4 +22,5 @@
 
 	delivery_settings = frappe.get_doc("Delivery Settings")
 	delivery_settings.dispatch_template = _("Dispatch Notification")
+	delivery_settings.flags.ignore_links = True
 	delivery_settings.save()
diff --git a/erpnext/patches/v12_0/create_itc_reversal_custom_fields.py b/erpnext/patches/v12_0/create_itc_reversal_custom_fields.py
index d157aad..d4fbded 100644
--- a/erpnext/patches/v12_0/create_itc_reversal_custom_fields.py
+++ b/erpnext/patches/v12_0/create_itc_reversal_custom_fields.py
@@ -97,6 +97,8 @@
 				'itc_central_tax': 0,
 				'itc_cess_amount': 0
 			})
+			if not gst_accounts:
+				continue
 
 			if d.account_head in gst_accounts.get('igst_account'):
 				amount_map[d.parent]['itc_integrated_tax'] += d.amount
diff --git a/erpnext/patches/v13_0/add_default_interview_notification_templates.py b/erpnext/patches/v13_0/add_default_interview_notification_templates.py
index 0208ca9..6b5de52 100644
--- a/erpnext/patches/v13_0/add_default_interview_notification_templates.py
+++ b/erpnext/patches/v13_0/add_default_interview_notification_templates.py
@@ -32,4 +32,5 @@
 	hr_settings = frappe.get_doc('HR Settings')
 	hr_settings.interview_reminder_template = _('Interview Reminder')
 	hr_settings.feedback_reminder_notification_template = _('Interview Feedback Reminder')
+	hr_settings.flags.ignore_links = True
 	hr_settings.save()
diff --git a/erpnext/patches/v14_0/add_default_exit_questionnaire_notification_template.py b/erpnext/patches/v14_0/add_default_exit_questionnaire_notification_template.py
index 8b1752b..120182a 100644
--- a/erpnext/patches/v14_0/add_default_exit_questionnaire_notification_template.py
+++ b/erpnext/patches/v14_0/add_default_exit_questionnaire_notification_template.py
@@ -24,4 +24,5 @@
 
 	hr_settings = frappe.get_doc("HR Settings")
 	hr_settings.exit_questionnaire_notification_template = template
+	hr_settings.flags.ignore_links = True
 	hr_settings.save()
diff --git a/erpnext/public/js/controllers/transaction.js b/erpnext/public/js/controllers/transaction.js
index 773d53c..3791741 100644
--- a/erpnext/public/js/controllers/transaction.js
+++ b/erpnext/public/js/controllers/transaction.js
@@ -680,7 +680,7 @@
 		var item = frappe.get_doc(cdt, cdn);
 		frappe.model.round_floats_in(item, ["price_list_rate", "discount_percentage"]);
 
-		// check if child doctype is Sales Order Item/Qutation Item and calculate the rate
+		// check if child doctype is Sales Order Item/Quotation Item and calculate the rate
 		if (in_list(["Quotation Item", "Sales Order Item", "Delivery Note Item", "Sales Invoice Item", "POS Invoice Item", "Purchase Invoice Item", "Purchase Order Item", "Purchase Receipt Item"]), cdt)
 			this.apply_pricing_rule_on_item(item);
 		else
@@ -1582,25 +1582,27 @@
 
 	_set_values_for_item_list(children) {
 		var me = this;
-		var price_list_rate_changed = false;
 		var items_rule_dict = {};
 
 		for(var i=0, l=children.length; i<l; i++) {
-			var d = children[i];
+			var d = children[i] ;
+			let item_row = frappe.get_doc(d.doctype, d.name);
 			var existing_pricing_rule = frappe.model.get_value(d.doctype, d.name, "pricing_rules");
 			for(var k in d) {
 				var v = d[k];
 				if (["doctype", "name"].indexOf(k)===-1) {
 					if(k=="price_list_rate") {
-						if(flt(v) != flt(d.price_list_rate)) price_list_rate_changed = true;
+						item_row['rate'] = v;
 					}
 
 					if (k !== 'free_item_data') {
-						frappe.model.set_value(d.doctype, d.name, k, v);
+						item_row[k] = v;
 					}
 				}
 			}
 
+			frappe.model.round_floats_in(item_row, ["price_list_rate", "discount_percentage"]);
+
 			// if pricing rule set as blank from an existing value, apply price_list
 			if(!me.frm.doc.ignore_pricing_rule && existing_pricing_rule && !d.pricing_rules) {
 				me.apply_price_list(frappe.get_doc(d.doctype, d.name));
@@ -1617,9 +1619,10 @@
 			}
 		}
 
+		me.frm.refresh_field('items');
 		me.apply_rule_on_other_items(items_rule_dict);
 
-		if(!price_list_rate_changed) me.calculate_taxes_and_totals();
+		me.calculate_taxes_and_totals();
 	}
 
 	apply_rule_on_other_items(args) {
diff --git a/erpnext/selling/doctype/customer/customer.py b/erpnext/selling/doctype/customer/customer.py
index 0c8c53a..b7f74df 100644
--- a/erpnext/selling/doctype/customer/customer.py
+++ b/erpnext/selling/doctype/customer/customer.py
@@ -196,20 +196,19 @@
 			if not lead.lead_name:
 				frappe.throw(_("Please mention the Lead Name in Lead {0}").format(self.lead_name))
 
-			if lead.company_name:
-				contact_names = frappe.get_all('Dynamic Link', filters={
-									"parenttype":"Contact",
-									"link_doctype":"Lead",
-									"link_name":self.lead_name
-								}, fields=["parent as name"])
+			contact_names = frappe.get_all('Dynamic Link', filters={
+								"parenttype":"Contact",
+								"link_doctype":"Lead",
+								"link_name":self.lead_name
+							}, fields=["parent as name"])
 
-				for contact_name in contact_names:
-					contact = frappe.get_doc('Contact', contact_name.get('name'))
-					if not contact.has_link('Customer', self.name):
-						contact.append('links', dict(link_doctype='Customer', link_name=self.name))
-						contact.save(ignore_permissions=self.flags.ignore_permissions)
+			for contact_name in contact_names:
+				contact = frappe.get_doc('Contact', contact_name.get('name'))
+				if not contact.has_link('Customer', self.name):
+					contact.append('links', dict(link_doctype='Customer', link_name=self.name))
+					contact.save(ignore_permissions=self.flags.ignore_permissions)
 
-			else:
+			if not contact_names:
 				lead.lead_name = lead.lead_name.lstrip().split(" ")
 				lead.first_name = lead.lead_name[0]
 				lead.last_name = " ".join(lead.lead_name[1:])
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 82e5d0c..0c0acc7 100644
--- a/erpnext/selling/report/sales_order_analysis/sales_order_analysis.py
+++ b/erpnext/selling/report/sales_order_analysis/sales_order_analysis.py
@@ -61,6 +61,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,
+			IF((SELECT pending_qty) = 0, (TO_SECONDS(Max(dn.posting_date))-TO_SECONDS(so.transaction_date)), 0) as time_taken_to_deliver,
 			IFNULL(SUM(sii.qty), 0) as billed_qty,
 			soi.base_amount as amount,
 			(soi.delivered_qty * soi.base_rate) as delivered_qty_amount,
@@ -70,9 +71,13 @@
 			so.company, soi.name
 		FROM
 			`tabSales Order` so,
-			`tabSales Order Item` soi
+			(`tabSales Order Item` soi
 		LEFT JOIN `tabSales Invoice Item` sii
-			ON sii.so_detail = soi.name and sii.docstatus = 1
+			ON sii.so_detail = soi.name and sii.docstatus = 1)
+		LEFT JOIN `tabDelivery Note Item` dni
+			on dni.so_detail = soi.name
+		RIGHT JOIN `tabDelivery Note` dn
+			on dni.parent = dn.name and dn.docstatus = 1
 		WHERE
 			soi.parent = so.name
 			and so.status not in ('Stopped', 'Closed', 'On Hold')
@@ -259,6 +264,12 @@
 			"fieldname": "delay",
 			"fieldtype": "Data",
 			"width": 100
+		},
+		{
+			"label": _("Time Taken to Deliver"),
+			"fieldname": "time_taken_to_deliver",
+			"fieldtype": "Duration",
+			"width": 100
 		}
 	])
 	if not filters.get("group_by_so"):
diff --git a/erpnext/stock/doctype/stock_ledger_entry/stock_ledger_entry.json b/erpnext/stock/doctype/stock_ledger_entry/stock_ledger_entry.json
index 2651407..46ce9de 100644
--- a/erpnext/stock/doctype/stock_ledger_entry/stock_ledger_entry.json
+++ b/erpnext/stock/doctype/stock_ledger_entry/stock_ledger_entry.json
@@ -150,7 +150,7 @@
    "fieldtype": "Float",
    "in_filter": 1,
    "in_list_view": 1,
-   "label": "Actual Quantity",
+   "label": "Qty Change",
    "oldfieldname": "actual_qty",
    "oldfieldtype": "Currency",
    "print_width": "150px",
@@ -189,7 +189,7 @@
    "fieldname": "qty_after_transaction",
    "fieldtype": "Float",
    "in_filter": 1,
-   "label": "Actual Qty After Transaction",
+   "label": "Qty After Transaction",
    "oldfieldname": "bin_aqat",
    "oldfieldtype": "Currency",
    "print_width": "150px",
@@ -210,7 +210,7 @@
   {
    "fieldname": "stock_value",
    "fieldtype": "Currency",
-   "label": "Stock Value",
+   "label": "Balance Stock Value",
    "oldfieldname": "stock_value",
    "oldfieldtype": "Currency",
    "options": "Company:company:default_currency",
@@ -219,14 +219,14 @@
   {
    "fieldname": "stock_value_difference",
    "fieldtype": "Currency",
-   "label": "Stock Value Difference",
+   "label": "Change in Stock Value",
    "options": "Company:company:default_currency",
    "read_only": 1
   },
   {
    "fieldname": "stock_queue",
    "fieldtype": "Text",
-   "label": "Stock Queue (FIFO)",
+   "label": "FIFO Stock Queue (qty, rate)",
    "oldfieldname": "fcfs_stack",
    "oldfieldtype": "Text",
    "print_hide": 1,
@@ -317,10 +317,11 @@
  "in_create": 1,
  "index_web_pages_for_search": 1,
  "links": [],
- "modified": "2021-10-08 13:42:51.857631",
+ "modified": "2021-12-21 06:25:30.040801",
  "modified_by": "Administrator",
  "module": "Stock",
  "name": "Stock Ledger Entry",
+ "naming_rule": "Expression (old style)",
  "owner": "Administrator",
  "permissions": [
   {
@@ -338,5 +339,6 @@
   }
  ],
  "sort_field": "modified",
- "sort_order": "DESC"
-}
+ "sort_order": "DESC",
+ "states": []
+}
\ No newline at end of file
diff --git a/erpnext/stock/get_item_details.py b/erpnext/stock/get_item_details.py
index 9889a22..06f8fa7 100644
--- a/erpnext/stock/get_item_details.py
+++ b/erpnext/stock/get_item_details.py
@@ -1097,7 +1097,7 @@
 		}
 
 def apply_price_list_on_item(args):
-	item_doc = frappe.get_doc("Item", args.item_code)
+	item_doc = frappe.db.get_value("Item", args.item_code, ['name', 'variant_of'], as_dict=1)
 	item_details = get_price_list_rate(args, item_doc)
 
 	item_details.update(get_pricing_rule_for_item(args, item_details.price_list_rate))
diff --git a/erpnext/stock/report/stock_ledger_invariant_check/stock_ledger_invariant_check.js b/erpnext/stock/report/stock_ledger_invariant_check/stock_ledger_invariant_check.js
index c484516..31f389f 100644
--- a/erpnext/stock/report/stock_ledger_invariant_check/stock_ledger_invariant_check.js
+++ b/erpnext/stock/report/stock_ledger_invariant_check/stock_ledger_invariant_check.js
@@ -8,7 +8,8 @@
 	"fifo_value_diff",
 	"fifo_valuation_diff",
 	"valuation_diff",
-	"fifo_difference_diff"
+	"fifo_difference_diff",
+	"diff_value_diff"
 ];
 
 frappe.query_reports["Stock Ledger Invariant Check"] = {
diff --git a/erpnext/stock/report/stock_ledger_invariant_check/stock_ledger_invariant_check.py b/erpnext/stock/report/stock_ledger_invariant_check/stock_ledger_invariant_check.py
index ca47a1e..48753b0 100644
--- a/erpnext/stock/report/stock_ledger_invariant_check/stock_ledger_invariant_check.py
+++ b/erpnext/stock/report/stock_ledger_invariant_check/stock_ledger_invariant_check.py
@@ -50,6 +50,7 @@
 
 def add_invariant_check_fields(sles):
 	balance_qty = 0.0
+	balance_stock_value = 0.0
 	for idx, sle in enumerate(sles):
 		queue = json.loads(sle.stock_queue)
 
@@ -60,6 +61,7 @@
 			fifo_value += qty * rate
 
 		balance_qty += sle.actual_qty
+		balance_stock_value += sle.stock_value_difference
 		if sle.voucher_type == "Stock Reconciliation" and not sle.batch_no:
 			balance_qty = sle.qty_after_transaction
 
@@ -70,6 +72,7 @@
 			sle.stock_value / sle.qty_after_transaction if sle.qty_after_transaction else None
 		)
 		sle.expected_qty_after_transaction = balance_qty
+		sle.stock_value_from_diff = balance_stock_value
 
 		# set difference fields
 		sle.difference_in_qty = sle.qty_after_transaction - sle.expected_qty_after_transaction
@@ -81,6 +84,7 @@
 		sle.valuation_diff = (
 			sle.valuation_rate - sle.balance_value_by_qty if sle.balance_value_by_qty else None
 		)
+		sle.diff_value_diff = sle.stock_value_from_diff -  sle.stock_value
 
 		if idx > 0:
 			sle.fifo_stock_diff = sle.fifo_stock_value - sles[idx - 1].fifo_stock_value
@@ -191,13 +195,22 @@
 			"fieldtype": "Float",
 			"label": "D - E",
 		},
-
 		{
 			"fieldname": "stock_value_difference",
 			"fieldtype": "Float",
 			"label": "(F) Stock Value Difference",
 		},
 		{
+			"fieldname": "stock_value_from_diff",
+			"fieldtype": "Float",
+			"label": "Balance Stock Value using (F)",
+		},
+		{
+			"fieldname": "diff_value_diff",
+			"fieldtype": "Float",
+			"label": "K - D",
+		},
+		{
 			"fieldname": "fifo_stock_diff",
 			"fieldtype": "Float",
 			"label": "(G) Stock Value difference (FIFO queue)",
diff --git a/erpnext/support/doctype/issue/test_issue.py b/erpnext/support/doctype/issue/test_issue.py
index 14cec46..7a0a5e5 100644
--- a/erpnext/support/doctype/issue/test_issue.py
+++ b/erpnext/support/doctype/issue/test_issue.py
@@ -98,6 +98,7 @@
 		issue.save()
 
 		self.assertEqual(issue.on_hold_since, frappe.flags.current_time)
+		self.assertFalse(issue.resolution_by)
 
 		creation = get_datetime("2020-03-04 5:00")
 		frappe.flags.current_time = get_datetime("2020-03-04 5:00")
diff --git a/erpnext/support/doctype/service_level_agreement/service_level_agreement.py b/erpnext/support/doctype/service_level_agreement/service_level_agreement.py
index c94700b..b3348f1 100644
--- a/erpnext/support/doctype/service_level_agreement/service_level_agreement.py
+++ b/erpnext/support/doctype/service_level_agreement/service_level_agreement.py
@@ -476,7 +476,7 @@
 	priority = get_response_and_resolution_duration(doc)
 	start_date_time = get_datetime(doc.get("service_level_agreement_creation") or doc.creation)
 	set_response_by(doc, start_date_time, priority)
-	if apply_sla_for_resolution:
+	if apply_sla_for_resolution and not doc.get('on_hold_since'): # resolution_by is reset if on hold
 		set_resolution_by(doc, start_date_time, priority)
 
 
@@ -624,9 +624,6 @@
 	if doc.meta.has_field("user_resolution_time"):
 		doc.user_resolution_time = None
 
-	if doc.meta.has_field("agreement_status"):
-		doc.agreement_status = "First Response Due"
-
 
 # called via hooks on communication update
 def on_communication_update(doc, status):