revert: "fix: expected value after useful life validation"

diff --git a/codecov.yml b/codecov.yml
index 67bd445..1fa602a 100644
--- a/codecov.yml
+++ b/codecov.yml
@@ -8,6 +8,16 @@
         target: auto
         threshold: 0.5%
 
+    patch:
+      default:
+        target: 85%
+        threshold: 0%
+        base: auto
+        branches:
+          - develop
+        if_ci_failed: ignore
+        only_pulls: true
+
 comment:
   layout: "diff, files"
   require_changes: true
diff --git a/erpnext/buying/doctype/request_for_quotation/request_for_quotation.js b/erpnext/buying/doctype/request_for_quotation/request_for_quotation.js
index bde00cb..e7049fd 100644
--- a/erpnext/buying/doctype/request_for_quotation/request_for_quotation.js
+++ b/erpnext/buying/doctype/request_for_quotation/request_for_quotation.js
@@ -124,6 +124,14 @@
 		dialog.show()
 	},
 
+	schedule_date(frm) {
+		if(frm.doc.schedule_date){
+			frm.doc.items.forEach((item) => {
+				item.schedule_date = frm.doc.schedule_date;
+			})
+		}
+		refresh_field("items");
+	},
 	preview: (frm) => {
 		let dialog = new frappe.ui.Dialog({
 			title: __('Preview Email'),
@@ -184,7 +192,13 @@
 		dialog.show();
 	}
 })
-
+frappe.ui.form.on("Request for Quotation Item", {
+	items_add(frm, cdt, cdn) {
+		if (frm.doc.schedule_date) {
+			frappe.model.set_value(cdt, cdn, 'schedule_date', frm.doc.schedule_date);
+		}
+	}
+});
 frappe.ui.form.on("Request for Quotation Supplier",{
 	supplier: function(frm, cdt, cdn) {
 		var d = locals[cdt][cdn]
diff --git a/erpnext/buying/doctype/request_for_quotation/request_for_quotation.json b/erpnext/buying/doctype/request_for_quotation/request_for_quotation.json
index 4ce4100..4993df9 100644
--- a/erpnext/buying/doctype/request_for_quotation/request_for_quotation.json
+++ b/erpnext/buying/doctype/request_for_quotation/request_for_quotation.json
@@ -12,6 +12,7 @@
   "vendor",
   "column_break1",
   "transaction_date",
+  "schedule_date",
   "status",
   "amended_from",
   "suppliers_section",
@@ -246,16 +247,22 @@
    "fieldname": "sec_break_email_2",
    "fieldtype": "Section Break",
    "hide_border": 1
+  },
+  {
+   "fieldname": "schedule_date",
+   "fieldtype": "Date",
+   "label": "Required Date"
   }
  ],
  "icon": "fa fa-shopping-cart",
  "index_web_pages_for_search": 1,
  "is_submittable": 1,
  "links": [],
- "modified": "2020-11-05 22:04:29.017134",
+ "modified": "2021-11-24 17:47:49.909000",
  "modified_by": "Administrator",
  "module": "Buying",
  "name": "Request for Quotation",
+ "naming_rule": "By \"Naming Series\" field",
  "owner": "Administrator",
  "permissions": [
   {
diff --git a/erpnext/hr/doctype/exit_interview/test_exit_interview.py b/erpnext/hr/doctype/exit_interview/test_exit_interview.py
index a0bf9b3..8e076ed 100644
--- a/erpnext/hr/doctype/exit_interview/test_exit_interview.py
+++ b/erpnext/hr/doctype/exit_interview/test_exit_interview.py
@@ -19,7 +19,7 @@
 		frappe.db.sql('delete from `tabExit Interview`')
 
 	def test_duplicate_interview(self):
-		employee = make_employee('employeeexit1@example.com')
+		employee = make_employee('employeeexitint1@example.com')
 		frappe.db.set_value('Employee', employee, 'relieving_date', getdate())
 		interview = create_exit_interview(employee)
 
@@ -27,7 +27,7 @@
 		self.assertRaises(frappe.DuplicateEntryError, doc.save)
 
 	def test_relieving_date_validation(self):
-		employee = make_employee('employeeexit2@example.com')
+		employee = make_employee('employeeexitint2@example.com')
 		# unset relieving date
 		frappe.db.set_value('Employee', employee, 'relieving_date', None)
 
diff --git a/erpnext/hr/report/employee_exits/employee_exits.py b/erpnext/hr/report/employee_exits/employee_exits.py
index 8e0b07d..bde5a89 100644
--- a/erpnext/hr/report/employee_exits/employee_exits.py
+++ b/erpnext/hr/report/employee_exits/employee_exits.py
@@ -108,12 +108,11 @@
 				interview.status.as_('interview_status'), interview.employee_status.as_('employee_status'),
 				interview.reference_document_name.as_('questionnaire'), fnf.name.as_('full_and_final_statement'))
 			.distinct()
-			.orderby(employee.relieving_date, order=Order.asc)
 			.where(
 				((employee.relieving_date.isnotnull()) | (employee.relieving_date != ''))
 				& ((interview.name.isnull()) | ((interview.name.isnotnull()) & (interview.docstatus != 2)))
 				& ((fnf.name.isnull()) | ((fnf.name.isnotnull()) & (fnf.docstatus != 2)))
-			)
+			).orderby(employee.relieving_date, order=Order.asc)
 	)
 
 	query = get_conditions(filters, query, employee, interview, fnf)
diff --git a/erpnext/manufacturing/doctype/blanket_order/test_blanket_order.py b/erpnext/manufacturing/doctype/blanket_order/test_blanket_order.py
index d5db3fc..eff2344 100644
--- a/erpnext/manufacturing/doctype/blanket_order/test_blanket_order.py
+++ b/erpnext/manufacturing/doctype/blanket_order/test_blanket_order.py
@@ -1,17 +1,15 @@
 # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors
 # See license.txt
-
-import unittest
-
 import frappe
 from frappe.utils import add_months, today
 
 from erpnext import get_company_currency
+from erpnext.tests.utils import ERPNextTestCase
 
 from .blanket_order import make_order
 
 
-class TestBlanketOrder(unittest.TestCase):
+class TestBlanketOrder(ERPNextTestCase):
 	def setUp(self):
 		frappe.flags.args = frappe._dict()
 
diff --git a/erpnext/manufacturing/doctype/bom/test_bom.py b/erpnext/manufacturing/doctype/bom/test_bom.py
index 4c03230..178d92c 100644
--- a/erpnext/manufacturing/doctype/bom/test_bom.py
+++ b/erpnext/manufacturing/doctype/bom/test_bom.py
@@ -2,7 +2,6 @@
 # License: GNU General Public License v3. See license.txt
 
 
-import unittest
 from collections import deque
 from functools import partial
 
@@ -18,10 +17,11 @@
 	create_stock_reconciliation,
 )
 from erpnext.tests.test_subcontracting import set_backflush_based_on
+from erpnext.tests.utils import ERPNextTestCase
 
 test_records = frappe.get_test_records('BOM')
 
-class TestBOM(unittest.TestCase):
+class TestBOM(ERPNextTestCase):
 	def setUp(self):
 		if not frappe.get_value('Item', '_Test Item'):
 			make_test_records('Item')
diff --git a/erpnext/manufacturing/doctype/bom_update_tool/test_bom_update_tool.py b/erpnext/manufacturing/doctype/bom_update_tool/test_bom_update_tool.py
index 526c243..12576cb 100644
--- a/erpnext/manufacturing/doctype/bom_update_tool/test_bom_update_tool.py
+++ b/erpnext/manufacturing/doctype/bom_update_tool/test_bom_update_tool.py
@@ -1,19 +1,16 @@
 # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
 # License: GNU General Public License v3. See license.txt
 
-
-
-import unittest
-
 import frappe
 
 from erpnext.manufacturing.doctype.bom_update_tool.bom_update_tool import update_cost
 from erpnext.manufacturing.doctype.production_plan.test_production_plan import make_bom
 from erpnext.stock.doctype.item.test_item import create_item
+from erpnext.tests.utils import ERPNextTestCase
 
 test_records = frappe.get_test_records('BOM')
 
-class TestBOMUpdateTool(unittest.TestCase):
+class TestBOMUpdateTool(ERPNextTestCase):
 	def test_replace_bom(self):
 		current_bom = "BOM-_Test Item Home Desktop Manufactured-001"
 
diff --git a/erpnext/manufacturing/doctype/job_card/job_card.js b/erpnext/manufacturing/doctype/job_card/job_card.js
index 453ad50..dac7b36 100644
--- a/erpnext/manufacturing/doctype/job_card/job_card.js
+++ b/erpnext/manufacturing/doctype/job_card/job_card.js
@@ -75,6 +75,15 @@
 			&& (frm.doc.items || !frm.doc.items.length || frm.doc.for_quantity == frm.doc.transferred_qty)) {
 			frm.trigger("prepare_timer_buttons");
 		}
+
+		if (frm.doc.work_order) {
+			frappe.db.get_value('Work Order', frm.doc.work_order,
+				'transfer_material_against').then((r) => {
+				if (r.message.transfer_material_against == 'Work Order') {
+					frm.set_df_property('items', 'hidden', 1);
+				}
+			});
+		}
 	},
 
 	setup_corrective_job_card: function(frm) {
diff --git a/erpnext/manufacturing/doctype/job_card/test_job_card.py b/erpnext/manufacturing/doctype/job_card/test_job_card.py
index 9b4fc8b..bb5004b 100644
--- a/erpnext/manufacturing/doctype/job_card/test_job_card.py
+++ b/erpnext/manufacturing/doctype/job_card/test_job_card.py
@@ -1,6 +1,5 @@
 # Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and Contributors
 # See license.txt
-import unittest
 
 import frappe
 from frappe.utils import random_string
@@ -12,9 +11,10 @@
 from erpnext.manufacturing.doctype.work_order.test_work_order import make_wo_order_test_record
 from erpnext.manufacturing.doctype.workstation.test_workstation import make_workstation
 from erpnext.stock.doctype.stock_entry.stock_entry_utils import make_stock_entry
+from erpnext.tests.utils import ERPNextTestCase
 
 
-class TestJobCard(unittest.TestCase):
+class TestJobCard(ERPNextTestCase):
 	def setUp(self):
 		make_bom_for_jc_tests()
 
@@ -329,4 +329,4 @@
 	bom.rm_cost_as_per = "Valuation Rate"
 	bom.items[0].uom = "_Test UOM 1"
 	bom.items[0].conversion_factor = 5
-	bom.insert()
\ No newline at end of file
+	bom.insert()
diff --git a/erpnext/manufacturing/doctype/production_plan/test_production_plan.py b/erpnext/manufacturing/doctype/production_plan/test_production_plan.py
index a2980a7..2febc1e 100644
--- a/erpnext/manufacturing/doctype/production_plan/test_production_plan.py
+++ b/erpnext/manufacturing/doctype/production_plan/test_production_plan.py
@@ -1,8 +1,5 @@
 # Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and Contributors
 # See license.txt
-
-import unittest
-
 import frappe
 from frappe.utils import add_to_date, flt, now_datetime, nowdate
 
@@ -17,9 +14,10 @@
 from erpnext.stock.doctype.stock_reconciliation.test_stock_reconciliation import (
 	create_stock_reconciliation,
 )
+from erpnext.tests.utils import ERPNextTestCase
 
 
-class TestProductionPlan(unittest.TestCase):
+class TestProductionPlan(ERPNextTestCase):
 	def setUp(self):
 		for item in ['Test Production Item 1', 'Subassembly Item 1',
 			'Raw Material Item 1', 'Raw Material Item 2']:
diff --git a/erpnext/manufacturing/doctype/routing/test_routing.py b/erpnext/manufacturing/doctype/routing/test_routing.py
index 68d9dec..e90b0a7 100644
--- a/erpnext/manufacturing/doctype/routing/test_routing.py
+++ b/erpnext/manufacturing/doctype/routing/test_routing.py
@@ -1,17 +1,15 @@
 # Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors
 # See license.txt
-
-import unittest
-
 import frappe
 from frappe.test_runner import make_test_records
 
 from erpnext.manufacturing.doctype.job_card.job_card import OperationSequenceError
 from erpnext.manufacturing.doctype.work_order.test_work_order import make_wo_order_test_record
 from erpnext.stock.doctype.item.test_item import make_item
+from erpnext.tests.utils import ERPNextTestCase
 
 
-class TestRouting(unittest.TestCase):
+class TestRouting(ERPNextTestCase):
 	@classmethod
 	def setUpClass(cls):
 		cls.item_code = "Test Routing Item - A"
diff --git a/erpnext/manufacturing/doctype/work_order/test_work_order.py b/erpnext/manufacturing/doctype/work_order/test_work_order.py
index 1e74b6d..165e0ac 100644
--- a/erpnext/manufacturing/doctype/work_order/test_work_order.py
+++ b/erpnext/manufacturing/doctype/work_order/test_work_order.py
@@ -1,6 +1,5 @@
 # Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and Contributors
 # License: GNU General Public License v3. See license.txt
-import unittest
 
 import frappe
 from frappe.utils import add_months, cint, flt, now, today
@@ -95,7 +94,7 @@
 
 	def test_reserved_qty_for_partial_completion(self):
 		item = "_Test Item"
-		warehouse = create_warehouse("Test Warehouse for reserved_qty - _TC")
+		warehouse = "_Test Warehouse - _TC"
 
 		bin1_at_start = get_bin(item, warehouse)
 
diff --git a/erpnext/manufacturing/doctype/workstation/test_workstation.py b/erpnext/manufacturing/doctype/workstation/test_workstation.py
index 5ed5153..c298c0a 100644
--- a/erpnext/manufacturing/doctype/workstation/test_workstation.py
+++ b/erpnext/manufacturing/doctype/workstation/test_workstation.py
@@ -1,8 +1,5 @@
 # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors and Contributors
 # See license.txt
-
-import unittest
-
 import frappe
 from frappe.test_runner import make_test_records
 
@@ -13,12 +10,13 @@
 	WorkstationHolidayError,
 	check_if_within_operating_hours,
 )
+from erpnext.tests.utils import ERPNextTestCase
 
 test_dependencies = ["Warehouse"]
 test_records = frappe.get_test_records('Workstation')
 make_test_records('Workstation')
 
-class TestWorkstation(unittest.TestCase):
+class TestWorkstation(ERPNextTestCase):
 	def test_validate_timings(self):
 		check_if_within_operating_hours("_Test Workstation 1", "Operation 1", "2013-02-02 11:00:00", "2013-02-02 19:00:00")
 		check_if_within_operating_hours("_Test Workstation 1", "Operation 1", "2013-02-02 10:00:00", "2013-02-02 20:00:00")
diff --git a/erpnext/patches.txt b/erpnext/patches.txt
index 0687b42..65ad79e 100644
--- a/erpnext/patches.txt
+++ b/erpnext/patches.txt
@@ -165,6 +165,7 @@
 erpnext.patches.v12_0.set_default_payroll_based_on
 erpnext.patches.v12_0.repost_stock_ledger_entries_for_target_warehouse
 erpnext.patches.v12_0.update_end_date_and_status_in_email_campaign
+erpnext.patches.v13_0.validate_options_for_data_field
 erpnext.patches.v13_0.move_tax_slabs_from_payroll_period_to_income_tax_slab #123
 erpnext.patches.v12_0.fix_quotation_expired_status
 erpnext.patches.v12_0.rename_pos_closing_doctype
@@ -287,7 +288,6 @@
 erpnext.patches.v14_0.delete_einvoicing_doctypes
 erpnext.patches.v13_0.custom_fields_for_taxjar_integration          #08-11-2021
 erpnext.patches.v13_0.set_operation_time_based_on_operating_cost
-erpnext.patches.v13_0.validate_options_for_data_field
 erpnext.patches.v13_0.create_gst_payment_entry_fields #27-11-2021
 erpnext.patches.v14_0.delete_shopify_doctypes
 erpnext.patches.v13_0.fix_invoice_statuses
diff --git a/erpnext/patches/v13_0/rename_ksa_qr_field.py b/erpnext/patches/v13_0/rename_ksa_qr_field.py
index 0bb86e0..f4f9b17 100644
--- a/erpnext/patches/v13_0/rename_ksa_qr_field.py
+++ b/erpnext/patches/v13_0/rename_ksa_qr_field.py
@@ -2,6 +2,7 @@
 # License: GNU General Public License v3. See license.txt
 
 import frappe
+from frappe.custom.doctype.custom_field.custom_field import create_custom_fields
 from frappe.model.utils.rename_field import rename_field
 
 
@@ -12,5 +13,20 @@
 
 	if frappe.db.exists('DocType', 'Sales Invoice'):
 		frappe.reload_doc('accounts', 'doctype', 'sales_invoice', force=True)
+
+		# rename_field method assumes that the field already exists or the doc is synced
+		if not frappe.db.has_column('Sales Invoice', 'ksa_einv_qr'):
+			create_custom_fields({
+				'Sales Invoice': [
+					dict(
+						fieldname='ksa_einv_qr',
+						label='KSA E-Invoicing QR',
+						fieldtype='Attach Image',
+						read_only=1, no_copy=1, hidden=1
+					)
+				]
+			})
+
 		if frappe.db.has_column('Sales Invoice', 'qr_code'):
 			rename_field('Sales Invoice', 'qr_code', 'ksa_einv_qr')
+			frappe.delete_doc_if_exists("Custom Field", "Sales Invoice-qr_code")
diff --git a/erpnext/payroll/doctype/salary_slip/salary_slip.py b/erpnext/payroll/doctype/salary_slip/salary_slip.py
index 05af09e..b035292 100644
--- a/erpnext/payroll/doctype/salary_slip/salary_slip.py
+++ b/erpnext/payroll/doctype/salary_slip/salary_slip.py
@@ -940,10 +940,12 @@
 
 	def get_amount_based_on_payment_days(self, row, joining_date, relieving_date):
 		amount, additional_amount = row.amount, row.additional_amount
+		timesheet_component = frappe.db.get_value("Salary Structure", self.salary_structure, "salary_component")
+
 		if (self.salary_structure and
 			cint(row.depends_on_payment_days) and cint(self.total_working_days)
 			and not (row.additional_salary and row.default_amount) # to identify overwritten additional salary
-			and (not self.salary_slip_based_on_timesheet or
+			and (row.salary_component != timesheet_component or
 				getdate(self.start_date) < joining_date or
 				(relieving_date and getdate(self.end_date) > relieving_date)
 			)):
@@ -952,7 +954,7 @@
 			amount = flt((flt(row.default_amount) * flt(self.payment_days)
 				/ cint(self.total_working_days)), row.precision("amount")) + additional_amount
 
-		elif not self.payment_days and not self.salary_slip_based_on_timesheet and cint(row.depends_on_payment_days):
+		elif not self.payment_days and row.salary_component != timesheet_component and cint(row.depends_on_payment_days):
 			amount, additional_amount = 0, 0
 		elif not row.amount:
 			amount = flt(row.default_amount) + flt(row.additional_amount)
diff --git a/erpnext/payroll/doctype/salary_slip/test_salary_slip.py b/erpnext/payroll/doctype/salary_slip/test_salary_slip.py
index e4618c3..3052a2b 100644
--- a/erpnext/payroll/doctype/salary_slip/test_salary_slip.py
+++ b/erpnext/payroll/doctype/salary_slip/test_salary_slip.py
@@ -134,6 +134,57 @@
 
 		frappe.db.set_value("Payroll Settings", None, "payroll_based_on", "Leave")
 
+	def test_payment_days_in_salary_slip_based_on_timesheet(self):
+		from erpnext.hr.doctype.attendance.attendance import mark_attendance
+		from erpnext.projects.doctype.timesheet.test_timesheet import (
+			make_salary_structure_for_timesheet,
+			make_timesheet,
+		)
+		from erpnext.projects.doctype.timesheet.timesheet import (
+			make_salary_slip as make_salary_slip_for_timesheet,
+		)
+
+		# Payroll based on attendance
+		frappe.db.set_value("Payroll Settings", None, "payroll_based_on", "Attendance")
+
+		emp = make_employee("test_employee_timesheet@salary.com", company="_Test Company")
+		frappe.db.set_value("Employee", emp, {"relieving_date": None, "status": "Active"})
+
+		# mark attendance
+		month_start_date = get_first_day(nowdate())
+		month_end_date = get_last_day(nowdate())
+
+		first_sunday = frappe.db.sql("""
+			select holiday_date from `tabHoliday`
+			where parent = 'Salary Slip Test Holiday List'
+				and holiday_date between %s and %s
+			order by holiday_date
+		""", (month_start_date, month_end_date))[0][0]
+
+		mark_attendance(emp, add_days(first_sunday, 1), 'Absent', ignore_validate=True) # counted as absent
+
+		# salary structure based on timesheet
+		make_salary_structure_for_timesheet(emp)
+		timesheet = make_timesheet(emp, simulate=True, is_billable=1)
+		salary_slip = make_salary_slip_for_timesheet(timesheet.name)
+		salary_slip.start_date = month_start_date
+		salary_slip.end_date = month_end_date
+		salary_slip.save()
+		salary_slip.submit()
+
+		no_of_days = self.get_no_of_days()
+		days_in_month = no_of_days[0]
+		no_of_holidays = no_of_days[1]
+
+		self.assertEqual(salary_slip.payment_days, days_in_month - no_of_holidays - 1)
+
+		# gross pay calculation based on attendance (payment days)
+		gross_pay = 78100 - ((78000 / (days_in_month - no_of_holidays)) * flt(salary_slip.leave_without_pay + salary_slip.absent_days))
+
+		self.assertEqual(salary_slip.gross_pay, flt(gross_pay, 2))
+
+		frappe.db.set_value("Payroll Settings", None, "payroll_based_on", "Leave")
+
 	def test_component_amount_dependent_on_another_payment_days_based_component(self):
 		from erpnext.hr.doctype.attendance.attendance import mark_attendance
 		from erpnext.payroll.doctype.salary_structure.test_salary_structure import (
diff --git a/erpnext/projects/doctype/timesheet/test_timesheet.py b/erpnext/projects/doctype/timesheet/test_timesheet.py
index d59cc01..148d8ba 100644
--- a/erpnext/projects/doctype/timesheet/test_timesheet.py
+++ b/erpnext/projects/doctype/timesheet/test_timesheet.py
@@ -34,10 +34,6 @@
 		for dt in ["Salary Slip", "Salary Structure", "Salary Structure Assignment", "Timesheet"]:
 			frappe.db.sql("delete from `tab%s`" % dt)
 
-		if not frappe.db.exists("Salary Component", "Timesheet Component"):
-			frappe.get_doc({"doctype": "Salary Component", "salary_component": "Timesheet Component"}).insert()
-
-
 	def test_timesheet_billing_amount(self):
 		emp = make_employee("test_employee_6@salary.com")
 
@@ -160,6 +156,9 @@
 	salary_structure_name = "Timesheet Salary Structure Test"
 	frequency = "Monthly"
 
+	if not frappe.db.exists("Salary Component", "Timesheet Component"):
+		frappe.get_doc({"doctype": "Salary Component", "salary_component": "Timesheet Component"}).insert()
+
 	salary_structure = make_salary_structure(salary_structure_name, frequency, company=company, dont_submit=True)
 	salary_structure.salary_component = "Timesheet Component"
 	salary_structure.salary_slip_based_on_timesheet = 1
diff --git a/erpnext/regional/report/hsn_wise_summary_of_outward_supplies/hsn_wise_summary_of_outward_supplies.py b/erpnext/regional/report/hsn_wise_summary_of_outward_supplies/hsn_wise_summary_of_outward_supplies.py
index e03ad37..1c1335e 100644
--- a/erpnext/regional/report/hsn_wise_summary_of_outward_supplies/hsn_wise_summary_of_outward_supplies.py
+++ b/erpnext/regional/report/hsn_wise_summary_of_outward_supplies/hsn_wise_summary_of_outward_supplies.py
@@ -114,9 +114,11 @@
 
 	items = frappe.db.sql("""
 		select
-			`tabSales Invoice Item`.name, `tabSales Invoice Item`.base_price_list_rate,
-			`tabSales Invoice Item`.gst_hsn_code, `tabSales Invoice Item`.stock_qty,
-			`tabSales Invoice Item`.stock_uom, `tabSales Invoice Item`.base_net_amount,
+			`tabSales Invoice Item`.gst_hsn_code,
+			`tabSales Invoice Item`.stock_uom,
+			sum(`tabSales Invoice Item`.stock_qty) as stock_qty,
+			sum(`tabSales Invoice Item`.base_net_amount) as base_net_amount,
+			sum(`tabSales Invoice Item`.base_price_list_rate) as base_price_list_rate,
 			`tabSales Invoice Item`.parent, `tabSales Invoice Item`.item_code,
 			`tabGST HSN Code`.description
 		from `tabSales Invoice`, `tabSales Invoice Item`, `tabGST HSN Code`
@@ -124,6 +126,8 @@
 			and `tabSales Invoice`.docstatus = 1
 			and `tabSales Invoice Item`.gst_hsn_code is not NULL
 			and `tabSales Invoice Item`.gst_hsn_code = `tabGST HSN Code`.name %s %s
+		group by
+			`tabSales Invoice Item`.parent, `tabSales Invoice Item`.item_code
 
 		""" % (conditions, match_conditions), filters, as_dict=1)
 
diff --git a/erpnext/regional/report/hsn_wise_summary_of_outward_supplies/test_hsn_wise_summary_of_outward_supplies.py b/erpnext/regional/report/hsn_wise_summary_of_outward_supplies/test_hsn_wise_summary_of_outward_supplies.py
new file mode 100644
index 0000000..86dc458
--- /dev/null
+++ b/erpnext/regional/report/hsn_wise_summary_of_outward_supplies/test_hsn_wise_summary_of_outward_supplies.py
@@ -0,0 +1,89 @@
+# Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and contributors
+# For license information, please see license.txt
+
+
+from unittest import TestCase
+
+import frappe
+
+from erpnext.accounts.doctype.sales_invoice.test_sales_invoice import create_sales_invoice
+from erpnext.regional.doctype.gstr_3b_report.test_gstr_3b_report import (
+	make_company as setup_company,
+)
+from erpnext.regional.doctype.gstr_3b_report.test_gstr_3b_report import (
+	make_customers as setup_customers,
+)
+from erpnext.regional.doctype.gstr_3b_report.test_gstr_3b_report import (
+	set_account_heads as setup_gst_settings,
+)
+from erpnext.regional.report.hsn_wise_summary_of_outward_supplies.hsn_wise_summary_of_outward_supplies import (
+	execute as run_report,
+)
+from erpnext.stock.doctype.item.test_item import make_item
+
+
+class TestHSNWiseSummaryReport(TestCase):
+	@classmethod
+	def setUpClass(cls):
+		setup_company()
+		setup_customers()
+		setup_gst_settings()
+		make_item("Golf Car", properties={ "gst_hsn_code": "999900" })
+
+	@classmethod
+	def tearDownClass(cls):
+		frappe.db.rollback()
+
+	def test_hsn_summary_for_invoice_with_duplicate_items(self):
+		si = create_sales_invoice(
+			company="_Test Company GST",
+			customer = "_Test GST Customer",
+			currency = "INR",
+			warehouse = "Finished Goods - _GST",
+			debit_to = "Debtors - _GST",
+			income_account = "Sales - _GST",
+			expense_account = "Cost of Goods Sold - _GST",
+			cost_center = "Main - _GST",
+			do_not_save=1
+		)
+
+		si.items = []
+		si.append("items", {
+			"item_code": "Golf Car",
+			"gst_hsn_code": "999900",
+			"qty": "1",
+			"rate": "120",
+			"cost_center": "Main - _GST"
+		})
+		si.append("items", {
+			"item_code": "Golf Car",
+			"gst_hsn_code": "999900",
+			"qty": "1",
+			"rate": "140",
+			"cost_center": "Main - _GST"
+		})
+		si.append("taxes", {
+			"charge_type": "On Net Total",
+			"account_head": "Output Tax IGST - _GST",
+			"cost_center": "Main - _GST",
+			"description": "IGST @ 18.0",
+			"rate": 18
+		})
+		si.posting_date = "2020-11-17"
+		si.submit()
+		si.reload()
+
+		[columns, data] = run_report(filters=frappe._dict({
+			"company": "_Test Company GST",
+			"gst_hsn_code": "999900",
+			"company_gstin": si.company_gstin,
+			"from_date": si.posting_date,
+			"to_date": si.posting_date
+		}))
+
+		filtered_rows = list(filter(lambda row: row['gst_hsn_code'] == "999900", data))
+		self.assertTrue(filtered_rows)
+
+		hsn_row = filtered_rows[0]
+		self.assertEquals(hsn_row['stock_qty'], 2.0)
+		self.assertEquals(hsn_row['total_amount'], 306.8)
diff --git a/erpnext/selling/doctype/customer/test_customer.py b/erpnext/selling/doctype/customer/test_customer.py
index 7d6b74d..5301fd0 100644
--- a/erpnext/selling/doctype/customer/test_customer.py
+++ b/erpnext/selling/doctype/customer/test_customer.py
@@ -2,8 +2,6 @@
 # License: GNU General Public License v3. See license.txt
 
 
-import unittest
-
 import frappe
 from frappe.test_runner import make_test_records
 from frappe.utils import flt
@@ -11,7 +9,7 @@
 from erpnext.accounts.party import get_due_date
 from erpnext.exceptions import PartyDisabled, PartyFrozen
 from erpnext.selling.doctype.customer.customer import get_credit_limit, get_customer_outstanding
-from erpnext.tests.utils import create_test_contact_and_address
+from erpnext.tests.utils import ERPNextTestCase, create_test_contact_and_address
 
 test_ignore = ["Price List"]
 test_dependencies = ['Payment Term', 'Payment Terms Template']
@@ -19,7 +17,7 @@
 
 
 
-class TestCustomer(unittest.TestCase):
+class TestCustomer(ERPNextTestCase):
 	def setUp(self):
 		if not frappe.get_value('Item', '_Test Item'):
 			make_test_records('Item')
diff --git a/erpnext/selling/doctype/party_specific_item/test_party_specific_item.py b/erpnext/selling/doctype/party_specific_item/test_party_specific_item.py
index 874a364..b951044 100644
--- a/erpnext/selling/doctype/party_specific_item/test_party_specific_item.py
+++ b/erpnext/selling/doctype/party_specific_item/test_party_specific_item.py
@@ -6,6 +6,7 @@
 import frappe
 
 from erpnext.controllers.queries import item_query
+from erpnext.tests.utils import ERPNextTestCase
 
 test_dependencies = ['Item', 'Customer', 'Supplier']
 
@@ -17,7 +18,7 @@
 	psi.based_on_value = args.get('based_on_value')
 	psi.insert()
 
-class TestPartySpecificItem(unittest.TestCase):
+class TestPartySpecificItem(ERPNextTestCase):
 	def setUp(self):
 		self.customer = frappe.get_last_doc("Customer")
 		self.supplier = frappe.get_last_doc("Supplier")
diff --git a/erpnext/selling/doctype/quotation/test_quotation.py b/erpnext/selling/doctype/quotation/test_quotation.py
index aa83726..4357201 100644
--- a/erpnext/selling/doctype/quotation/test_quotation.py
+++ b/erpnext/selling/doctype/quotation/test_quotation.py
@@ -1,15 +1,15 @@
 # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
 # License: GNU General Public License v3. See license.txt
 
-import unittest
-
 import frappe
 from frappe.utils import add_days, add_months, flt, getdate, nowdate
 
+from erpnext.tests.utils import ERPNextTestCase
+
 test_dependencies = ["Product Bundle"]
 
 
-class TestQuotation(unittest.TestCase):
+class TestQuotation(ERPNextTestCase):
 	def test_make_quotation_without_terms(self):
 		quotation = make_quotation(do_not_save=1)
 		self.assertFalse(quotation.get('payment_schedule'))
diff --git a/erpnext/selling/doctype/sales_order/test_sales_order.py b/erpnext/selling/doctype/sales_order/test_sales_order.py
index 2a0752e..42bc0b7 100644
--- a/erpnext/selling/doctype/sales_order/test_sales_order.py
+++ b/erpnext/selling/doctype/sales_order/test_sales_order.py
@@ -2,7 +2,6 @@
 # License: GNU General Public License v3. See license.txt
 
 import json
-import unittest
 
 import frappe
 import frappe.permissions
@@ -28,12 +27,14 @@
 )
 from erpnext.stock.doctype.item.test_item import make_item
 from erpnext.stock.doctype.stock_entry.stock_entry_utils import make_stock_entry
+from erpnext.tests.utils import ERPNextTestCase
 
 
-class TestSalesOrder(unittest.TestCase):
+class TestSalesOrder(ERPNextTestCase):
 
 	@classmethod
 	def setUpClass(cls):
+		super().setUpClass()
 		cls.unlink_setting = int(frappe.db.get_value("Accounts Settings", "Accounts Settings",
 			"unlink_advance_payment_on_cancelation_of_order"))
 
@@ -42,6 +43,7 @@
 		# reset config to previous state
 		frappe.db.set_value("Accounts Settings", "Accounts Settings",
 			"unlink_advance_payment_on_cancelation_of_order", cls.unlink_setting)
+		super().tearDownClass()
 
 	def tearDown(self):
 		frappe.set_user("Administrator")
diff --git a/erpnext/selling/report/pending_so_items_for_purchase_request/test_pending_so_items_for_purchase_request.py b/erpnext/selling/report/pending_so_items_for_purchase_request/test_pending_so_items_for_purchase_request.py
index 9c30afc..d62915f 100644
--- a/erpnext/selling/report/pending_so_items_for_purchase_request/test_pending_so_items_for_purchase_request.py
+++ b/erpnext/selling/report/pending_so_items_for_purchase_request/test_pending_so_items_for_purchase_request.py
@@ -2,8 +2,6 @@
 # For license information, please see license.txt
 
 
-import unittest
-
 from frappe.utils import add_months, nowdate
 
 from erpnext.selling.doctype.sales_order.sales_order import make_material_request
@@ -11,9 +9,10 @@
 from erpnext.selling.report.pending_so_items_for_purchase_request.pending_so_items_for_purchase_request import (
 	execute,
 )
+from erpnext.tests.utils import ERPNextTestCase
 
 
-class TestPendingSOItemsForPurchaseRequest(unittest.TestCase):
+class TestPendingSOItemsForPurchaseRequest(ERPNextTestCase):
     def test_result_for_partial_material_request(self):
         so = make_sales_order()
         mr=make_material_request(so.name)
diff --git a/erpnext/selling/report/sales_analytics/test_analytics.py b/erpnext/selling/report/sales_analytics/test_analytics.py
index 8ffc5d6..f56cce2 100644
--- a/erpnext/selling/report/sales_analytics/test_analytics.py
+++ b/erpnext/selling/report/sales_analytics/test_analytics.py
@@ -2,15 +2,14 @@
 # For license information, please see license.txt
 
 
-import unittest
-
 import frappe
 
 from erpnext.selling.doctype.sales_order.test_sales_order import make_sales_order
 from erpnext.selling.report.sales_analytics.sales_analytics import execute
+from erpnext.tests.utils import ERPNextTestCase
 
 
-class TestAnalytics(unittest.TestCase):
+class TestAnalytics(ERPNextTestCase):
 	def test_sales_analytics(self):
 		frappe.db.sql("delete from `tabSales Order` where company='_Test Company 2'")
 
diff --git a/erpnext/stock/doctype/bin/bin.py b/erpnext/stock/doctype/bin/bin.py
index a33134b..37b5411 100644
--- a/erpnext/stock/doctype/bin/bin.py
+++ b/erpnext/stock/doctype/bin/bin.py
@@ -43,9 +43,9 @@
 				frappe.qb
 					.from_(wo)
 					.from_(wo_item)
-					.select(Case()
-							.when(wo.skip_transfer == 0, Sum(wo_item.required_qty - wo_item.transferred_qty))
-							.else_(Sum(wo_item.required_qty - wo_item.consumed_qty))
+					.select(Sum(Case()
+							.when(wo.skip_transfer == 0, wo_item.required_qty - wo_item.transferred_qty)
+							.else_(wo_item.required_qty - wo_item.consumed_qty))
 						)
 					.where(
 						(wo_item.item_code == self.item_code)
diff --git a/erpnext/stock/doctype/item/item.json b/erpnext/stock/doctype/item/item.json
index 4f4e691..29abd45 100644
--- a/erpnext/stock/doctype/item/item.json
+++ b/erpnext/stock/doctype/item/item.json
@@ -361,8 +361,7 @@
    "fieldname": "valuation_method",
    "fieldtype": "Select",
    "label": "Valuation Method",
-   "options": "\nFIFO\nMoving Average",
-   "set_only_once": 1
+   "options": "\nFIFO\nMoving Average"
   },
   {
    "depends_on": "is_stock_item",
@@ -1035,7 +1034,7 @@
  "image_field": "image",
  "index_web_pages_for_search": 1,
  "links": [],
- "modified": "2021-12-03 08:32:03.869294",
+ "modified": "2021-12-14 04:13:16.857534",
  "modified_by": "Administrator",
  "module": "Stock",
  "name": "Item",
diff --git a/erpnext/stock/doctype/packing_slip_item/packing_slip_item.json b/erpnext/stock/doctype/packing_slip_item/packing_slip_item.json
index 29c4193..4270839 100644
--- a/erpnext/stock/doctype/packing_slip_item/packing_slip_item.json
+++ b/erpnext/stock/doctype/packing_slip_item/packing_slip_item.json
@@ -1,451 +1,140 @@
 {
- "allow_copy": 0, 
- "allow_import": 0, 
- "allow_rename": 0, 
- "autoname": "hash", 
- "beta": 0, 
- "creation": "2013-04-08 13:10:16", 
- "custom": 0, 
- "docstatus": 0, 
- "doctype": "DocType", 
- "document_type": "Document", 
- "editable_grid": 1, 
- "engine": "InnoDB", 
+ "actions": [],
+ "autoname": "hash",
+ "creation": "2013-04-08 13:10:16",
+ "doctype": "DocType",
+ "document_type": "Document",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "field_order": [
+  "item_code",
+  "column_break_2",
+  "item_name",
+  "batch_no",
+  "desc_section",
+  "description",
+  "quantity_section",
+  "qty",
+  "net_weight",
+  "column_break_10",
+  "stock_uom",
+  "weight_uom",
+  "page_break",
+  "dn_detail"
+ ],
  "fields": [
   {
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "fieldname": "item_code", 
-   "fieldtype": "Link", 
-   "hidden": 0, 
-   "ignore_user_permissions": 0, 
-   "ignore_xss_filter": 0, 
-   "in_filter": 0, 
-   "in_global_search": 1, 
-   "in_list_view": 1, 
-   "in_standard_filter": 0, 
-   "label": "Item Code", 
-   "length": 0, 
-   "no_copy": 0, 
-   "options": "Item", 
-   "permlevel": 0, 
-   "print_hide": 0, 
-   "print_hide_if_no_value": 0, 
-   "print_width": "100px", 
-   "read_only": 0, 
-   "remember_last_selected_value": 0, 
-   "report_hide": 0, 
-   "reqd": 1, 
-   "search_index": 0, 
-   "set_only_once": 0, 
-   "unique": 0, 
+   "fieldname": "item_code",
+   "fieldtype": "Link",
+   "in_global_search": 1,
+   "in_list_view": 1,
+   "label": "Item Code",
+   "options": "Item",
+   "print_width": "100px",
+   "reqd": 1,
    "width": "100px"
-  }, 
+  },
   {
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "fieldname": "column_break_2", 
-   "fieldtype": "Column Break", 
-   "hidden": 0, 
-   "ignore_user_permissions": 0, 
-   "ignore_xss_filter": 0, 
-   "in_filter": 0, 
-   "in_global_search": 0, 
-   "in_list_view": 0, 
-   "in_standard_filter": 0, 
-   "length": 0, 
-   "no_copy": 0, 
-   "permlevel": 0, 
-   "precision": "", 
-   "print_hide": 0, 
-   "print_hide_if_no_value": 0, 
-   "read_only": 0, 
-   "remember_last_selected_value": 0, 
-   "report_hide": 0, 
-   "reqd": 0, 
-   "search_index": 0, 
-   "set_only_once": 0, 
-   "unique": 0
-  }, 
+   "fieldname": "column_break_2",
+   "fieldtype": "Column Break"
+  },
   {
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "fieldname": "item_name", 
-   "fieldtype": "Data", 
-   "hidden": 0, 
-   "ignore_user_permissions": 0, 
-   "ignore_xss_filter": 0, 
-   "in_filter": 0, 
-   "in_global_search": 0, 
-   "in_list_view": 1, 
-   "in_standard_filter": 0, 
-   "label": "Item Name", 
-   "length": 0, 
-   "no_copy": 0, 
-   "options": "item_code.item_name",
-   "permlevel": 0, 
-   "print_hide": 0, 
-   "print_hide_if_no_value": 0, 
-   "print_width": "200px", 
-   "read_only": 1, 
-   "remember_last_selected_value": 0, 
-   "report_hide": 0, 
-   "reqd": 0, 
-   "search_index": 0, 
-   "set_only_once": 0, 
-   "unique": 0, 
+   "fetch_from": "item_code.item_name",
+   "fieldname": "item_name",
+   "fieldtype": "Data",
+   "in_list_view": 1,
+   "label": "Item Name",
+   "print_width": "200px",
+   "read_only": 1,
    "width": "200px"
-  }, 
+  },
   {
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "fieldname": "batch_no", 
-   "fieldtype": "Link", 
-   "hidden": 0, 
-   "ignore_user_permissions": 0, 
-   "ignore_xss_filter": 0, 
-   "in_filter": 0, 
-   "in_global_search": 0, 
-   "in_list_view": 0, 
-   "in_standard_filter": 0, 
-   "label": "Batch No", 
-   "length": 0, 
-   "no_copy": 0, 
-   "options": "Batch", 
-   "permlevel": 0, 
-   "precision": "", 
-   "print_hide": 0, 
-   "print_hide_if_no_value": 0, 
-   "read_only": 0, 
-   "remember_last_selected_value": 0, 
-   "report_hide": 0, 
-   "reqd": 0, 
-   "search_index": 0, 
-   "set_only_once": 0, 
-   "unique": 0
-  }, 
+   "fieldname": "batch_no",
+   "fieldtype": "Link",
+   "label": "Batch No",
+   "options": "Batch"
+  },
   {
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 1, 
-   "columns": 0, 
-   "fieldname": "desc_section", 
-   "fieldtype": "Section Break", 
-   "hidden": 0, 
-   "ignore_user_permissions": 0, 
-   "ignore_xss_filter": 0, 
-   "in_filter": 0, 
-   "in_global_search": 0, 
-   "in_list_view": 0, 
-   "in_standard_filter": 0, 
-   "label": "Description", 
-   "length": 0, 
-   "no_copy": 0, 
-   "permlevel": 0, 
-   "precision": "", 
-   "print_hide": 0, 
-   "print_hide_if_no_value": 0, 
-   "read_only": 0, 
-   "remember_last_selected_value": 0, 
-   "report_hide": 0, 
-   "reqd": 0, 
-   "search_index": 0, 
-   "set_only_once": 0, 
-   "unique": 0
-  }, 
+   "collapsible": 1,
+   "fieldname": "desc_section",
+   "fieldtype": "Section Break",
+   "label": "Description"
+  },
   {
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "fieldname": "description", 
-   "fieldtype": "Text Editor", 
-   "hidden": 0, 
-   "ignore_user_permissions": 0, 
-   "ignore_xss_filter": 0, 
-   "in_filter": 0, 
-   "in_global_search": 0, 
-   "in_list_view": 0, 
-   "in_standard_filter": 0, 
-   "label": "Description", 
-   "length": 0, 
-   "no_copy": 0, 
-   "permlevel": 0, 
-   "precision": "", 
-   "print_hide": 0, 
-   "print_hide_if_no_value": 0, 
-   "read_only": 0, 
-   "remember_last_selected_value": 0, 
-   "report_hide": 0, 
-   "reqd": 0, 
-   "search_index": 0, 
-   "set_only_once": 0, 
-   "unique": 0
-  }, 
+   "fieldname": "description",
+   "fieldtype": "Text Editor",
+   "label": "Description"
+  },
   {
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "fieldname": "quantity_section", 
-   "fieldtype": "Section Break", 
-   "hidden": 0, 
-   "ignore_user_permissions": 0, 
-   "ignore_xss_filter": 0, 
-   "in_filter": 0, 
-   "in_global_search": 0, 
-   "in_list_view": 0, 
-   "in_standard_filter": 0, 
-   "label": "Quantity", 
-   "length": 0, 
-   "no_copy": 0, 
-   "permlevel": 0, 
-   "precision": "", 
-   "print_hide": 0, 
-   "print_hide_if_no_value": 0, 
-   "read_only": 0, 
-   "remember_last_selected_value": 0, 
-   "report_hide": 0, 
-   "reqd": 0, 
-   "search_index": 0, 
-   "set_only_once": 0, 
-   "unique": 0
-  }, 
+   "fieldname": "quantity_section",
+   "fieldtype": "Section Break",
+   "label": "Quantity"
+  },
   {
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "fieldname": "qty", 
-   "fieldtype": "Float", 
-   "hidden": 0, 
-   "ignore_user_permissions": 0, 
-   "ignore_xss_filter": 0, 
-   "in_filter": 0, 
-   "in_global_search": 0, 
-   "in_list_view": 1, 
-   "in_standard_filter": 0, 
-   "label": "Quantity", 
-   "length": 0, 
-   "no_copy": 0, 
-   "permlevel": 0, 
-   "print_hide": 0, 
-   "print_hide_if_no_value": 0, 
-   "print_width": "100px", 
-   "read_only": 0, 
-   "remember_last_selected_value": 0, 
-   "report_hide": 0, 
-   "reqd": 1, 
-   "search_index": 0, 
-   "set_only_once": 0, 
-   "unique": 0, 
+   "fieldname": "qty",
+   "fieldtype": "Float",
+   "in_list_view": 1,
+   "label": "Quantity",
+   "print_width": "100px",
+   "reqd": 1,
    "width": "100px"
-  }, 
+  },
   {
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "fieldname": "net_weight", 
-   "fieldtype": "Float", 
-   "hidden": 0, 
-   "ignore_user_permissions": 0, 
-   "ignore_xss_filter": 0, 
-   "in_filter": 0, 
-   "in_global_search": 0, 
-   "in_list_view": 1, 
-   "in_standard_filter": 0, 
-   "label": "Net Weight", 
-   "length": 0, 
-   "no_copy": 0, 
-   "permlevel": 0, 
-   "print_hide": 0, 
-   "print_hide_if_no_value": 0, 
-   "print_width": "100px", 
-   "read_only": 0, 
-   "remember_last_selected_value": 0, 
-   "report_hide": 0, 
-   "reqd": 0, 
-   "search_index": 0, 
-   "set_only_once": 0, 
-   "unique": 0, 
+   "fieldname": "net_weight",
+   "fieldtype": "Float",
+   "in_list_view": 1,
+   "label": "Net Weight",
+   "print_width": "100px",
    "width": "100px"
-  }, 
+  },
   {
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "fieldname": "column_break_10", 
-   "fieldtype": "Column Break", 
-   "hidden": 0, 
-   "ignore_user_permissions": 0, 
-   "ignore_xss_filter": 0, 
-   "in_filter": 0, 
-   "in_global_search": 0, 
-   "in_list_view": 0, 
-   "in_standard_filter": 0, 
-   "length": 0, 
-   "no_copy": 0, 
-   "permlevel": 0, 
-   "precision": "", 
-   "print_hide": 0, 
-   "print_hide_if_no_value": 0, 
-   "read_only": 0, 
-   "remember_last_selected_value": 0, 
-   "report_hide": 0, 
-   "reqd": 0, 
-   "search_index": 0, 
-   "set_only_once": 0, 
-   "unique": 0
-  }, 
+   "fieldname": "column_break_10",
+   "fieldtype": "Column Break"
+  },
   {
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "fieldname": "stock_uom", 
-   "fieldtype": "Link", 
-   "hidden": 0, 
-   "ignore_user_permissions": 0, 
-   "ignore_xss_filter": 0, 
-   "in_filter": 0, 
-   "in_global_search": 0, 
-   "in_list_view": 0, 
-   "in_standard_filter": 0, 
-   "label": "UOM", 
-   "length": 0, 
-   "no_copy": 0, 
-   "options": "UOM", 
-   "permlevel": 0, 
-   "print_hide": 0, 
-   "print_hide_if_no_value": 0, 
-   "print_width": "100px", 
-   "read_only": 1, 
-   "remember_last_selected_value": 0, 
-   "report_hide": 0, 
-   "reqd": 0, 
-   "search_index": 0, 
-   "set_only_once": 0, 
-   "unique": 0, 
+   "fieldname": "stock_uom",
+   "fieldtype": "Link",
+   "label": "UOM",
+   "options": "UOM",
+   "print_width": "100px",
+   "read_only": 1,
    "width": "100px"
-  }, 
+  },
   {
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "fieldname": "weight_uom", 
-   "fieldtype": "Link", 
-   "hidden": 0, 
-   "ignore_user_permissions": 0, 
-   "ignore_xss_filter": 0, 
-   "in_filter": 0, 
-   "in_global_search": 0, 
-   "in_list_view": 0, 
-   "in_standard_filter": 0, 
-   "label": "Weight UOM", 
-   "length": 0, 
-   "no_copy": 0, 
-   "options": "UOM", 
-   "permlevel": 0, 
-   "print_hide": 0, 
-   "print_hide_if_no_value": 0, 
-   "print_width": "100px", 
-   "read_only": 0, 
-   "remember_last_selected_value": 0, 
-   "report_hide": 0, 
-   "reqd": 0, 
-   "search_index": 0, 
-   "set_only_once": 0, 
-   "unique": 0, 
+   "fieldname": "weight_uom",
+   "fieldtype": "Link",
+   "label": "Weight UOM",
+   "options": "UOM",
+   "print_width": "100px",
    "width": "100px"
-  }, 
+  },
   {
-   "allow_on_submit": 1, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "fieldname": "page_break", 
-   "fieldtype": "Check", 
-   "hidden": 0, 
-   "ignore_user_permissions": 0, 
-   "ignore_xss_filter": 0, 
-   "in_filter": 0, 
-   "in_global_search": 0, 
-   "in_list_view": 1, 
-   "in_standard_filter": 0, 
-   "label": "Page Break", 
-   "length": 0, 
-   "no_copy": 0, 
-   "permlevel": 0, 
-   "print_hide": 0, 
-   "print_hide_if_no_value": 0, 
-   "read_only": 0, 
-   "remember_last_selected_value": 0, 
-   "report_hide": 0, 
-   "reqd": 0, 
-   "search_index": 0, 
-   "set_only_once": 0, 
-   "unique": 0
-  }, 
+   "allow_on_submit": 1,
+   "default": "0",
+   "fieldname": "page_break",
+   "fieldtype": "Check",
+   "in_list_view": 1,
+   "label": "Page Break"
+  },
   {
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "fieldname": "dn_detail", 
-   "fieldtype": "Data", 
-   "hidden": 1, 
-   "ignore_user_permissions": 0, 
-   "ignore_xss_filter": 0, 
-   "in_filter": 0, 
-   "in_global_search": 0, 
-   "in_list_view": 1, 
-   "in_standard_filter": 0, 
-   "label": "DN Detail", 
-   "length": 0, 
-   "no_copy": 0, 
-   "permlevel": 0, 
-   "print_hide": 0, 
-   "print_hide_if_no_value": 0, 
-   "read_only": 0, 
-   "remember_last_selected_value": 0, 
-   "report_hide": 0, 
-   "reqd": 0, 
-   "search_index": 0, 
-   "set_only_once": 0, 
-   "unique": 0
+   "fieldname": "dn_detail",
+   "fieldtype": "Data",
+   "hidden": 1,
+   "in_list_view": 1,
+   "label": "DN Detail"
   }
- ], 
- "hide_heading": 0, 
- "hide_toolbar": 0, 
- "idx": 1, 
- "image_view": 0, 
- "in_create": 0, 
-
- "is_submittable": 0, 
- "issingle": 0, 
- "istable": 1, 
- "max_attachments": 0, 
- "modified": "2018-06-01 07:21:58.220980",
- "modified_by": "Administrator", 
- "module": "Stock", 
- "name": "Packing Slip Item", 
- "owner": "Administrator", 
- "permissions": [], 
- "quick_entry": 0, 
- "read_only": 0, 
- "read_only_onload": 0, 
- "show_name_in_global_search": 0, 
- "track_changes": 1, 
- "track_seen": 0
+ ],
+ "idx": 1,
+ "istable": 1,
+ "links": [],
+ "modified": "2021-12-14 01:22:00.715935",
+ "modified_by": "Administrator",
+ "module": "Stock",
+ "name": "Packing Slip Item",
+ "naming_rule": "Random",
+ "owner": "Administrator",
+ "permissions": [],
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "track_changes": 1
 }
\ No newline at end of file
diff --git a/erpnext/stock/report/itemwise_recommended_reorder_level/itemwise_recommended_reorder_level.py b/erpnext/stock/report/itemwise_recommended_reorder_level/itemwise_recommended_reorder_level.py
index 314f160..3f49065 100644
--- a/erpnext/stock/report/itemwise_recommended_reorder_level/itemwise_recommended_reorder_level.py
+++ b/erpnext/stock/report/itemwise_recommended_reorder_level/itemwise_recommended_reorder_level.py
@@ -48,6 +48,7 @@
 	conditions = [get_item_group_condition(filters.get("item_group"))]
 	if filters.get("brand"):
 		conditions.append("item.brand=%(brand)s")
+	conditions.append("is_stock_item = 1")
 
 	return frappe.db.sql("""select name, item_name, description, brand, item_group,
 		safety_stock, lead_time_days from `tabItem` item where {}"""
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 50f31fd..c94700b 100644
--- a/erpnext/support/doctype/service_level_agreement/service_level_agreement.py
+++ b/erpnext/support/doctype/service_level_agreement/service_level_agreement.py
@@ -420,13 +420,13 @@
 	if is_open_status(prev_status) and is_hold_status(doc.status):
 		# Issue is on hold -> Set on_hold_since
 		doc.on_hold_since = now_time
+		reset_expected_response_and_resolution(doc)
 
 	# Replied to Open
 	if is_hold_status(prev_status) and is_open_status(doc.status):
 		# Issue was on hold -> Calculate Total Hold Time
 		calculate_hold_hours()
 		# Issue is open -> reset resolution_date
-		reset_expected_response_and_resolution(doc)
 		reset_resolution_metrics(doc)
 
 	# Open to Closed
@@ -440,7 +440,6 @@
 		# Issue was closed -> Calculate Total Hold Time from resolution_date
 		calculate_hold_hours()
 		# Issue is open -> reset resolution_date
-		reset_expected_response_and_resolution(doc)
 		reset_resolution_metrics(doc)
 
 	# Closed to Replied
@@ -449,6 +448,7 @@
 		calculate_hold_hours()
 		# Issue is on hold -> Set on_hold_since
 		doc.on_hold_since = now_time
+		reset_expected_response_and_resolution(doc)
 
 	# Replied to Closed
 	if is_hold_status(prev_status) and is_fulfilled_status(doc.status):
@@ -640,28 +640,35 @@
 	if not parent.meta.has_field('service_level_agreement'):
 		return
 
-	for_resolution = frappe.db.get_value('Service Level Agreement', parent.service_level_agreement, 'apply_sla_for_resolution')
-
 	if (
 		doc.sent_or_received == "Received" # a reply is received
 		and parent.get('status') == 'Open' # issue status is set as open from communication.py
-		and parent._doc_before_save
+		and parent.get_doc_before_save()
 		and parent.get('status') != parent._doc_before_save.get('status') # status changed
 	):
 		# undo the status change in db
 		# since prev status is fetched from db
-		frappe.db.set_value(parent.doctype, parent.name, 'status', parent._doc_before_save.get('status'))
+		frappe.db.set_value(
+			parent.doctype, parent.name,
+			'status', parent._doc_before_save.get('status'),
+			update_modified=False
+		)
 
 	elif (
 		doc.sent_or_received == "Sent" # a reply is sent
 		and parent.get('first_responded_on') # first_responded_on is set from communication.py
-		and parent._doc_before_save
+		and parent.get_doc_before_save()
 		and not parent._doc_before_save.get('first_responded_on') # first_responded_on was not set
 	):
 		# reset first_responded_on since it will be handled/set later on
 		parent.first_responded_on = None
 		parent.flags.on_first_reply = True
 
+	else:
+		return
+
+	for_resolution = frappe.db.get_value('Service Level Agreement', parent.service_level_agreement, 'apply_sla_for_resolution')
+
 	handle_status_change(parent, for_resolution)
 	update_response_and_resolution_metrics(parent, for_resolution)
 	update_agreement_status(parent, for_resolution)
@@ -670,12 +677,10 @@
 
 
 def reset_expected_response_and_resolution(doc):
-	update_values = {}
 	if doc.meta.has_field("first_responded_on") and not doc.get('first_responded_on'):
-		update_values['response_by'] = None
+		doc.response_by = None
 	if doc.meta.has_field("resolution_by") and not doc.get('resolution_date'):
-		update_values['resolution_by'] = None
-	doc.db_set(update_values)
+		doc.resolution_by = None
 
 
 def set_response_by(doc, start_date_time, priority):