Merge pull request #29270 from nextchamp-saqib/change-fieldtype

fix: threshold fields shows incorrect currency
diff --git a/.github/ISSUE_TEMPLATE/bug_report.yaml b/.github/ISSUE_TEMPLATE/bug_report.yaml
index 8f93811..4d61f1f 100644
--- a/.github/ISSUE_TEMPLATE/bug_report.yaml
+++ b/.github/ISSUE_TEMPLATE/bug_report.yaml
@@ -40,6 +40,7 @@
         - HR
         - projects
         - support
+        - CRM
         - assets
         - integrations
         - quality
@@ -48,6 +49,7 @@
         - agriculture
         - education
         - non-profit
+        - other
     validations:
       required: true
 
diff --git a/.github/labeler.yml b/.github/labeler.yml
index fc3f06d..3aaba71 100644
--- a/.github/labeler.yml
+++ b/.github/labeler.yml
@@ -1,53 +1,53 @@
 accounts:
-- 'erpnext/accounts/*'
-- 'erpnext/controllers/accounts_controller.py'
-- 'erpnext/controllers/taxes_and_totals.py'
+- erpnext/accounts/*
+- erpnext/controllers/accounts_controller.py
+- erpnext/controllers/taxes_and_totals.py
 
 stock:
-- 'erpnext/stock/*'
-- 'erpnext/controllers/stock_controller.py'
-- 'erpnext/controllers/item_variant.py'
+- erpnext/stock/*
+- erpnext/controllers/stock_controller.py
+- erpnext/controllers/item_variant.py
 
 assets:
-- 'erpnext/assets/*'
+- erpnext/assets/*
 
 regional:
-- 'erpnext/regional/*'
+- erpnext/regional/*
 
 selling:
-- 'erpnext/selling/*'
-- 'erpnext/controllers/selling_controller.py'
+- erpnext/selling/*
+- erpnext/controllers/selling_controller.py
 
 buying:
-- 'erpnext/buying/*'
-- 'erpnext/controllers/buying_controller.py'
+- erpnext/buying/*
+- erpnext/controllers/buying_controller.py
 
 support:
-- 'erpnext/support/*'
+- erpnext/support/*
 
 POS:
-- 'pos*'
+- pos*
 
 ecommerce:
-- 'erpnext/e_commerce/*'
+- erpnext/e_commerce/*
 
 maintenance:
-- 'erpnext/maintenance/*'
+- erpnext/maintenance/*
 
 manufacturing:
-- 'erpnext/manufacturing/*'
+- erpnext/manufacturing/*
 
 crm:
-- 'erpnext/crm/*'
+- erpnext/crm/*
 
 HR:
-- 'erpnext/hr/*'
+- erpnext/hr/*
 
 payroll:
-- 'erpnext/payroll*'
+- erpnext/payroll*
 
 projects:
-- 'erpnext/projects/*'
+- erpnext/projects/*
 
 # Any python files modifed but no test files modified
 needs-tests:
diff --git a/erpnext/accounts/doctype/payment_entry/payment_entry.py b/erpnext/accounts/doctype/payment_entry/payment_entry.py
index c1b056b..0e07abd 100644
--- a/erpnext/accounts/doctype/payment_entry/payment_entry.py
+++ b/erpnext/accounts/doctype/payment_entry/payment_entry.py
@@ -1708,7 +1708,10 @@
 
 def apply_early_payment_discount(paid_amount, received_amount, doc):
 	total_discount = 0
-	if doc.doctype in ['Sales Invoice', 'Purchase Invoice'] and doc.payment_schedule:
+	eligible_for_payments = ['Sales Order', 'Sales Invoice', 'Purchase Order', 'Purchase Invoice']
+	has_payment_schedule = hasattr(doc, 'payment_schedule') and doc.payment_schedule
+
+	if doc.doctype in eligible_for_payments and has_payment_schedule:
 		for term in doc.payment_schedule:
 			if not term.discounted_amount and term.discount and getdate(nowdate()) <= term.discount_date:
 				if term.discount_type == 'Percentage':
diff --git a/erpnext/accounts/report/deferred_revenue_and_expense/deferred_revenue_and_expense.py b/erpnext/accounts/report/deferred_revenue_and_expense/deferred_revenue_and_expense.py
index a4842c1..3a51db8 100644
--- a/erpnext/accounts/report/deferred_revenue_and_expense/deferred_revenue_and_expense.py
+++ b/erpnext/accounts/report/deferred_revenue_and_expense/deferred_revenue_and_expense.py
@@ -121,20 +121,21 @@
 		"""
 		simulate future posting by creating dummy gl entries. starts from the last posting date.
 		"""
-		if add_days(self.last_entry_date, 1) < self.period_list[-1].to_date:
-			self.estimate_for_period_list = get_period_list(
-				self.filters.from_fiscal_year,
-				self.filters.to_fiscal_year,
-				add_days(self.last_entry_date, 1),
-				self.period_list[-1].to_date,
-				"Date Range",
-				"Monthly",
-				company=self.filters.company,
-			)
-			for period in self.estimate_for_period_list:
-				amount = self.calculate_amount(period.from_date, period.to_date)
-				gle = self.make_dummy_gle(period.key, period.to_date, amount)
-				self.gle_entries.append(gle)
+		if self.service_start_date != self.service_end_date:
+			if add_days(self.last_entry_date, 1) < self.period_list[-1].to_date:
+				self.estimate_for_period_list = get_period_list(
+					self.filters.from_fiscal_year,
+					self.filters.to_fiscal_year,
+					add_days(self.last_entry_date, 1),
+					self.period_list[-1].to_date,
+					"Date Range",
+					"Monthly",
+					company=self.filters.company,
+				)
+				for period in self.estimate_for_period_list:
+					amount = self.calculate_amount(period.from_date, period.to_date)
+					gle = self.make_dummy_gle(period.key, period.to_date, amount)
+					self.gle_entries.append(gle)
 
 	def calculate_item_revenue_expense_for_period(self):
 		"""
diff --git a/erpnext/assets/doctype/asset/asset.py b/erpnext/assets/doctype/asset/asset.py
index a18b03a..ee3ec8e 100644
--- a/erpnext/assets/doctype/asset/asset.py
+++ b/erpnext/assets/doctype/asset/asset.py
@@ -608,7 +608,17 @@
 		return purchase_document
 
 	def get_fixed_asset_account(self):
-		return get_asset_category_account('fixed_asset_account', None, self.name, None, self.asset_category, self.company)
+		fixed_asset_account = get_asset_category_account('fixed_asset_account', None, self.name, None, self.asset_category, self.company)
+		if not fixed_asset_account:
+			frappe.throw(
+				_("Set {0} in asset category {1} for company {2}").format(
+					frappe.bold("Fixed Asset Account"),
+					frappe.bold(self.asset_category),
+					frappe.bold(self.company),
+				),
+				title=_("Account not Found"),
+			)
+		return fixed_asset_account
 
 	def get_cwip_account(self, cwip_enabled=False):
 		cwip_account = None
diff --git a/erpnext/controllers/tests/test_queries.py b/erpnext/controllers/tests/test_queries.py
index 05541d1..908d78c 100644
--- a/erpnext/controllers/tests/test_queries.py
+++ b/erpnext/controllers/tests/test_queries.py
@@ -1,6 +1,8 @@
 import unittest
 from functools import partial
 
+import frappe
+
 from erpnext.controllers import queries
 
 
@@ -85,3 +87,6 @@
 
 		wh = query(filters=[["Bin", "item_code", "=", "_Test Item"]])
 		self.assertGreaterEqual(len(wh), 1)
+
+	def test_default_uoms(self):
+		self.assertGreaterEqual(frappe.db.count("UOM", {"enabled": 1}), 10)
diff --git a/erpnext/controllers/tests/test_transaction_base.py b/erpnext/controllers/tests/test_transaction_base.py
index 13aa697..f4d3f97 100644
--- a/erpnext/controllers/tests/test_transaction_base.py
+++ b/erpnext/controllers/tests/test_transaction_base.py
@@ -4,19 +4,72 @@
 
 
 class TestUtils(unittest.TestCase):
-    def test_reset_default_field_value(self):
-        doc = frappe.get_doc({
-            "doctype": "Purchase Receipt",
-            "set_warehouse": "Warehouse 1",
-        })
+	def test_reset_default_field_value(self):
+		doc = frappe.get_doc({
+			"doctype": "Purchase Receipt",
+			"set_warehouse": "Warehouse 1",
+		})
 
-        # Same values
-        doc.items = [{"warehouse": "Warehouse 1"}, {"warehouse": "Warehouse 1"}, {"warehouse": "Warehouse 1"}]
-        doc.reset_default_field_value("set_warehouse", "items", "warehouse")
-        self.assertEqual(doc.set_warehouse, "Warehouse 1")
+		# Same values
+		doc.items = [{"warehouse": "Warehouse 1"}, {"warehouse": "Warehouse 1"}, {"warehouse": "Warehouse 1"}]
+		doc.reset_default_field_value("set_warehouse", "items", "warehouse")
+		self.assertEqual(doc.set_warehouse, "Warehouse 1")
 
-        # Mixed values
-        doc.items = [{"warehouse": "Warehouse 1"}, {"warehouse": "Warehouse 2"}, {"warehouse": "Warehouse 1"}]
-        doc.reset_default_field_value("set_warehouse", "items", "warehouse")
-        self.assertEqual(doc.set_warehouse, None)
+		# Mixed values
+		doc.items = [{"warehouse": "Warehouse 1"}, {"warehouse": "Warehouse 2"}, {"warehouse": "Warehouse 1"}]
+		doc.reset_default_field_value("set_warehouse", "items", "warehouse")
+		self.assertEqual(doc.set_warehouse, None)
 
+	def test_reset_default_field_value_in_mfg_stock_entry(self):
+		# manufacture stock entry with rows having blank source/target wh
+		se = frappe.get_doc(
+			doctype="Stock Entry",
+			purpose="Manufacture",
+			stock_entry_type="Manufacture",
+			company="_Test Company",
+			from_warehouse="_Test Warehouse - _TC",
+			to_warehouse="_Test Warehouse 1 - _TC",
+			items=[
+				frappe._dict(item_code="_Test Item", qty=1, basic_rate=200, s_warehouse="_Test Warehouse - _TC"),
+				frappe._dict(item_code="_Test FG Item", qty=4, t_warehouse="_Test Warehouse 1 - _TC", is_finished_item=1)
+			]
+		)
+		se.save()
+
+		# default fields must be untouched
+		self.assertEqual(se.from_warehouse, "_Test Warehouse - _TC")
+		self.assertEqual(se.to_warehouse, "_Test Warehouse 1 - _TC")
+
+		se.delete()
+
+	def test_reset_default_field_value_in_transfer_stock_entry(self):
+		doc = frappe.get_doc({
+			"doctype": "Stock Entry",
+			"purpose": "Material Receipt",
+			"from_warehouse": "Warehouse 1",
+			"to_warehouse": "Warehouse 2",
+		})
+
+		# Same values
+		doc.items = [
+			{"s_warehouse": "Warehouse 1", "t_warehouse": "Warehouse 2"},
+			{"s_warehouse": "Warehouse 1", "t_warehouse": "Warehouse 2"},
+			{"s_warehouse": "Warehouse 1", "t_warehouse": "Warehouse 2"}
+		]
+
+		doc.reset_default_field_value("from_warehouse", "items", "s_warehouse")
+		doc.reset_default_field_value("to_warehouse", "items", "t_warehouse")
+		self.assertEqual(doc.from_warehouse, "Warehouse 1")
+		self.assertEqual(doc.to_warehouse, "Warehouse 2")
+
+		# Mixed values in source wh
+		doc.items = [
+			{"s_warehouse": "Warehouse 1", "t_warehouse": "Warehouse 2"},
+			{"s_warehouse": "Warehouse 3", "t_warehouse": "Warehouse 2"},
+			{"s_warehouse": "Warehouse 1", "t_warehouse": "Warehouse 2"}
+		]
+
+		doc.reset_default_field_value("from_warehouse", "items", "s_warehouse")
+		doc.reset_default_field_value("to_warehouse", "items", "t_warehouse")
+		self.assertEqual(doc.from_warehouse, None)
+		self.assertEqual(doc.to_warehouse, "Warehouse 2")
\ No newline at end of file
diff --git a/erpnext/education/api.py b/erpnext/education/api.py
index d9013b0..636b948 100644
--- a/erpnext/education/api.py
+++ b/erpnext/education/api.py
@@ -201,8 +201,8 @@
 	conditions = get_event_conditions("Course Schedule", filters)
 
 	data = frappe.db.sql("""select name, course, color,
-			timestamp(schedule_date, from_time) as from_datetime,
-			timestamp(schedule_date, to_time) as to_datetime,
+			timestamp(schedule_date, from_time) as from_time,
+			timestamp(schedule_date, to_time) as to_time,
 			room, student_group, 0 as 'allDay'
 		from `tabCourse Schedule`
 		where ( schedule_date between %(start)s and %(end)s )
diff --git a/erpnext/education/doctype/course_schedule/course_schedule.py b/erpnext/education/doctype/course_schedule/course_schedule.py
index ffd323d..615d2c4 100644
--- a/erpnext/education/doctype/course_schedule/course_schedule.py
+++ b/erpnext/education/doctype/course_schedule/course_schedule.py
@@ -3,6 +3,8 @@
 # For license information, please see license.txt
 
 
+from datetime import datetime
+
 import frappe
 from frappe import _
 from frappe.model.document import Document
@@ -30,6 +32,14 @@
 		if self.from_time > self.to_time:
 			frappe.throw(_("From Time cannot be greater than To Time."))
 
+		"""Handles specicfic case to update schedule date in calendar """
+		if isinstance(self.from_time, str):
+			try:
+				datetime_obj = datetime.strptime(self.from_time, '%Y-%m-%d %H:%M:%S')
+				self.schedule_date = datetime_obj
+			except ValueError:
+				pass
+
 	def validate_overlap(self):
 		"""Validates overlap for Student Group, Instructor, Room"""
 
@@ -47,4 +57,4 @@
 			validate_overlap_for(self, "Assessment Plan", "student_group")
 
 		validate_overlap_for(self, "Assessment Plan", "room")
-		validate_overlap_for(self, "Assessment Plan", "supervisor", self.instructor)
+		validate_overlap_for(self, "Assessment Plan", "supervisor", self.instructor)
\ No newline at end of file
diff --git a/erpnext/education/doctype/course_schedule/course_schedule_calendar.js b/erpnext/education/doctype/course_schedule/course_schedule_calendar.js
index 803527e..cacd539 100644
--- a/erpnext/education/doctype/course_schedule/course_schedule_calendar.js
+++ b/erpnext/education/doctype/course_schedule/course_schedule_calendar.js
@@ -1,11 +1,10 @@
 frappe.views.calendar["Course Schedule"] = {
 	field_map: {
-		// from_datetime and to_datetime don't exist as docfields but are used in onload
-		"start": "from_datetime",
-		"end": "to_datetime",
+		"start": "from_time",
+		"end": "to_time",
 		"id": "name",
 		"title": "course",
-		"allDay": "allDay"
+		"allDay": "allDay",
 	},
 	gantt: false,
 	order_by: "schedule_date",
diff --git a/erpnext/education/doctype/course_schedule/test_course_schedule.py b/erpnext/education/doctype/course_schedule/test_course_schedule.py
index a732419..56149af 100644
--- a/erpnext/education/doctype/course_schedule/test_course_schedule.py
+++ b/erpnext/education/doctype/course_schedule/test_course_schedule.py
@@ -6,6 +6,7 @@
 
 import frappe
 from frappe.utils import to_timedelta, today
+from frappe.utils.data import add_to_date
 
 from erpnext.education.utils import OverlapError
 
@@ -39,6 +40,11 @@
 		make_course_schedule_test_record(from_time= cs1.from_time, to_time= cs1.to_time,
 			student_group="Course-TC102-2014-2015 (_Test Academic Term)", instructor="_Test Instructor 2", room=frappe.get_all("Room")[1].name)
 
+	def test_update_schedule_date(self):
+		doc = make_course_schedule_test_record(schedule_date= add_to_date(today(), days=1))
+		doc.schedule_date = add_to_date(doc.schedule_date, days=1)
+		doc.save()
+
 def make_course_schedule_test_record(**args):
 	args = frappe._dict(args)
 
diff --git a/erpnext/hr/doctype/employee_onboarding/test_employee_onboarding.py b/erpnext/hr/doctype/employee_onboarding/test_employee_onboarding.py
index cb1b560..2d129c8 100644
--- a/erpnext/hr/doctype/employee_onboarding/test_employee_onboarding.py
+++ b/erpnext/hr/doctype/employee_onboarding/test_employee_onboarding.py
@@ -19,7 +19,7 @@
 		if frappe.db.exists('Employee Onboarding', {'employee_name': 'Test Researcher'}):
 			frappe.delete_doc('Employee Onboarding', {'employee_name': 'Test Researcher'})
 
-		project = "Employee Onboarding : Test Researcher - test@researcher.com"
+		project = "Employee Onboarding : test@researcher.com"
 		frappe.db.sql("delete from tabProject where name=%s", project)
 		frappe.db.sql("delete from tabTask where project=%s", project)
 
@@ -27,7 +27,7 @@
 		onboarding = create_employee_onboarding()
 
 		project_name = frappe.db.get_value('Project', onboarding.project, 'project_name')
-		self.assertEqual(project_name, 'Employee Onboarding : Test Researcher - test@researcher.com')
+		self.assertEqual(project_name, 'Employee Onboarding : test@researcher.com')
 
 		# don't allow making employee if onboarding is not complete
 		self.assertRaises(IncompleteTaskError, make_employee, onboarding.name)
@@ -64,8 +64,8 @@
 
 
 def get_job_applicant():
-	if frappe.db.exists('Job Applicant', 'Test Researcher - test@researcher.com'):
-		return frappe.get_doc('Job Applicant', 'Test Researcher - test@researcher.com')
+	if frappe.db.exists('Job Applicant', 'test@researcher.com'):
+		return frappe.get_doc('Job Applicant', 'test@researcher.com')
 	applicant = frappe.new_doc('Job Applicant')
 	applicant.applicant_name = 'Test Researcher'
 	applicant.email_id = 'test@researcher.com'
diff --git a/erpnext/hr/doctype/job_applicant/job_applicant.json b/erpnext/hr/doctype/job_applicant/job_applicant.json
index 200f675..66b609c 100644
--- a/erpnext/hr/doctype/job_applicant/job_applicant.json
+++ b/erpnext/hr/doctype/job_applicant/job_applicant.json
@@ -192,10 +192,11 @@
  "idx": 1,
  "index_web_pages_for_search": 1,
  "links": [],
- "modified": "2021-09-29 23:06:10.904260",
+ "modified": "2022-01-12 16:28:53.196881",
  "modified_by": "Administrator",
  "module": "HR",
  "name": "Job Applicant",
+ "naming_rule": "Expression (old style)",
  "owner": "Administrator",
  "permissions": [
   {
@@ -210,10 +211,11 @@
    "write": 1
   }
  ],
- "search_fields": "applicant_name",
+ "search_fields": "applicant_name, email_id, job_title, phone_number",
  "sender_field": "email_id",
  "sort_field": "modified",
  "sort_order": "ASC",
+ "states": [],
  "subject_field": "notes",
  "title_field": "applicant_name"
 }
\ No newline at end of file
diff --git a/erpnext/hr/doctype/job_applicant/job_applicant.py b/erpnext/hr/doctype/job_applicant/job_applicant.py
index abaa50c..5b3d9bf 100644
--- a/erpnext/hr/doctype/job_applicant/job_applicant.py
+++ b/erpnext/hr/doctype/job_applicant/job_applicant.py
@@ -7,6 +7,7 @@
 import frappe
 from frappe import _
 from frappe.model.document import Document
+from frappe.model.naming import append_number_if_name_exists
 from frappe.utils import validate_email_address
 
 from erpnext.hr.doctype.interview.interview import get_interviewers
@@ -21,10 +22,11 @@
 			self.get("__onload").job_offer = job_offer[0].name
 
 	def autoname(self):
-		keys = filter(None, (self.applicant_name, self.email_id, self.job_title))
-		if not keys:
-			frappe.throw(_("Name or Email is mandatory"), frappe.NameError)
-		self.name = " - ".join(keys)
+		self.name = self.email_id
+
+		# applicant can apply more than once for a different job title or reapply
+		if frappe.db.exists("Job Applicant", self.name):
+			self.name = append_number_if_name_exists("Job Applicant", self.name)
 
 	def validate(self):
 		if self.email_id:
diff --git a/erpnext/hr/doctype/job_applicant/test_job_applicant.py b/erpnext/hr/doctype/job_applicant/test_job_applicant.py
index 36dcf6b..bf16220 100644
--- a/erpnext/hr/doctype/job_applicant/test_job_applicant.py
+++ b/erpnext/hr/doctype/job_applicant/test_job_applicant.py
@@ -9,7 +9,26 @@
 
 
 class TestJobApplicant(unittest.TestCase):
-	pass
+	def test_job_applicant_naming(self):
+		applicant = frappe.get_doc({
+			"doctype": "Job Applicant",
+			"status": "Open",
+			"applicant_name": "_Test Applicant",
+			"email_id": "job_applicant_naming@example.com"
+		}).insert()
+		self.assertEqual(applicant.name, 'job_applicant_naming@example.com')
+
+		applicant = frappe.get_doc({
+			"doctype": "Job Applicant",
+			"status": "Open",
+			"applicant_name": "_Test Applicant",
+			"email_id": "job_applicant_naming@example.com"
+		}).insert()
+		self.assertEqual(applicant.name, 'job_applicant_naming@example.com-1')
+
+	def tearDown(self):
+		frappe.db.rollback()
+
 
 def create_job_applicant(**args):
 	args = frappe._dict(args)
diff --git a/erpnext/hr/doctype/leave_period/leave_period.json b/erpnext/hr/doctype/leave_period/leave_period.json
index 9e895c3..84ce114 100644
--- a/erpnext/hr/doctype/leave_period/leave_period.json
+++ b/erpnext/hr/doctype/leave_period/leave_period.json
@@ -1,294 +1,108 @@
 {
- "allow_copy": 0,
- "allow_guest_to_view": 0,
+ "actions": [],
  "allow_import": 1,
  "allow_rename": 1,
  "autoname": "HR-LPR-.YYYY.-.#####",
- "beta": 0,
  "creation": "2018-04-13 15:20:52.864288",
- "custom": 0,
- "docstatus": 0,
  "doctype": "DocType",
- "document_type": "",
  "editable_grid": 1,
  "engine": "InnoDB",
+ "field_order": [
+  "from_date",
+  "to_date",
+  "is_active",
+  "column_break_3",
+  "company",
+  "optional_holiday_list"
+ ],
  "fields": [
   {
-   "allow_bulk_edit": 0,
-   "allow_in_quick_entry": 0,
-   "allow_on_submit": 0,
-   "bold": 0,
-   "collapsible": 0,
-   "columns": 0,
    "fieldname": "from_date",
    "fieldtype": "Date",
-   "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": "From Date",
-   "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": 1,
-   "search_index": 0,
-   "set_only_once": 0,
-   "translatable": 0,
-   "unique": 0
+   "reqd": 1
   },
   {
-   "allow_bulk_edit": 0,
-   "allow_in_quick_entry": 0,
-   "allow_on_submit": 0,
-   "bold": 0,
-   "collapsible": 0,
-   "columns": 0,
    "fieldname": "to_date",
    "fieldtype": "Date",
-   "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": "To Date",
-   "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": 1,
-   "search_index": 0,
-   "set_only_once": 0,
-   "translatable": 0,
-   "unique": 0
+   "reqd": 1
   },
   {
-   "allow_bulk_edit": 0,
-   "allow_in_quick_entry": 0,
-   "allow_on_submit": 0,
-   "bold": 0,
-   "collapsible": 0,
-   "columns": 0,
+   "default": "0",
    "fieldname": "is_active",
    "fieldtype": "Check",
-   "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": "Is Active",
-   "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,
-   "translatable": 0,
-   "unique": 0
+   "label": "Is Active"
   },
   {
-   "allow_bulk_edit": 0,
-   "allow_in_quick_entry": 0,
-   "allow_on_submit": 0,
-   "bold": 0,
-   "collapsible": 0,
-   "columns": 0,
    "fieldname": "column_break_3",
-   "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,
-   "translatable": 0,
-   "unique": 0
+   "fieldtype": "Column Break"
   },
   {
-   "allow_bulk_edit": 0,
-   "allow_in_quick_entry": 0,
-   "allow_on_submit": 0,
-   "bold": 0,
-   "collapsible": 0,
-   "columns": 0,
    "fieldname": "company",
    "fieldtype": "Link",
-   "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": "Company",
-   "length": 0,
-   "no_copy": 0,
    "options": "Company",
-   "permlevel": 0,
-   "precision": "",
-   "print_hide": 0,
-   "print_hide_if_no_value": 0,
-   "read_only": 0,
-   "remember_last_selected_value": 0,
-   "report_hide": 0,
-   "reqd": 1,
-   "search_index": 0,
-   "set_only_once": 0,
-   "translatable": 0,
-   "unique": 0
+   "reqd": 1
   },
   {
-   "allow_bulk_edit": 0,
-   "allow_in_quick_entry": 0,
-   "allow_on_submit": 0,
-   "bold": 0,
-   "collapsible": 0,
-   "columns": 0,
    "fieldname": "optional_holiday_list",
    "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": "Holiday List for Optional Leave",
-   "length": 0,
-   "no_copy": 0,
-   "options": "Holiday List",
-   "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,
-   "translatable": 0,
-   "unique": 0
+   "options": "Holiday List"
   }
  ],
- "has_web_view": 0,
- "hide_heading": 0,
- "hide_toolbar": 0,
- "idx": 0,
- "image_view": 0,
- "in_create": 0,
- "is_submittable": 0,
- "issingle": 0,
- "istable": 0,
- "max_attachments": 0,
- "modified": "2019-05-30 16:15:43.305502",
+ "links": [],
+ "modified": "2022-01-13 13:28:12.951025",
  "modified_by": "Administrator",
  "module": "HR",
  "name": "Leave Period",
- "name_case": "",
+ "naming_rule": "Expression (old style)",
  "owner": "Administrator",
  "permissions": [
   {
-   "amend": 0,
-   "cancel": 0,
    "create": 1,
    "delete": 1,
    "email": 1,
    "export": 1,
-   "if_owner": 0,
-   "import": 0,
-   "permlevel": 0,
    "print": 1,
    "read": 1,
    "report": 1,
    "role": "System Manager",
-   "set_user_permissions": 0,
    "share": 1,
-   "submit": 0,
    "write": 1
   },
   {
-   "amend": 0,
-   "cancel": 0,
    "create": 1,
    "delete": 1,
    "email": 1,
    "export": 1,
-   "if_owner": 0,
-   "import": 0,
-   "permlevel": 0,
    "print": 1,
    "read": 1,
    "report": 1,
    "role": "HR Manager",
-   "set_user_permissions": 0,
    "share": 1,
-   "submit": 0,
    "write": 1
   },
   {
-   "amend": 0,
-   "cancel": 0,
    "create": 1,
    "delete": 1,
    "email": 1,
    "export": 1,
-   "if_owner": 0,
-   "import": 0,
-   "permlevel": 0,
    "print": 1,
    "read": 1,
    "report": 1,
    "role": "HR User",
-   "set_user_permissions": 0,
    "share": 1,
-   "submit": 0,
    "write": 1
   }
  ],
- "quick_entry": 0,
- "read_only": 0,
- "read_only_onload": 0,
- "show_name_in_global_search": 0,
+ "search_fields": "from_date, to_date, company",
  "sort_field": "modified",
  "sort_order": "DESC",
- "track_changes": 1,
- "track_seen": 0,
- "track_views": 0
+ "states": [],
+ "track_changes": 1
 }
\ No newline at end of file
diff --git a/erpnext/hr/doctype/leave_policy_assignment/leave_policy_assignment.json b/erpnext/hr/doctype/leave_policy_assignment/leave_policy_assignment.json
index 3373350..27f0540 100644
--- a/erpnext/hr/doctype/leave_policy_assignment/leave_policy_assignment.json
+++ b/erpnext/hr/doctype/leave_policy_assignment/leave_policy_assignment.json
@@ -113,10 +113,11 @@
  ],
  "is_submittable": 1,
  "links": [],
- "modified": "2021-03-01 17:54:01.014509",
+ "modified": "2022-01-13 13:37:11.218882",
  "modified_by": "Administrator",
  "module": "HR",
  "name": "Leave Policy Assignment",
+ "naming_rule": "Expression (old style)",
  "owner": "Administrator",
  "permissions": [
   {
@@ -164,5 +165,7 @@
  ],
  "sort_field": "modified",
  "sort_order": "DESC",
+ "states": [],
+ "title_field": "employee_name",
  "track_changes": 1
 }
\ No newline at end of file
diff --git a/erpnext/hr/doctype/leave_policy_assignment/leave_policy_assignment_list.js b/erpnext/hr/doctype/leave_policy_assignment/leave_policy_assignment_list.js
index 8b954c4..6b75817 100644
--- a/erpnext/hr/doctype/leave_policy_assignment/leave_policy_assignment_list.js
+++ b/erpnext/hr/doctype/leave_policy_assignment/leave_policy_assignment_list.js
@@ -48,7 +48,16 @@
 						if (cur_dialog.fields_dict.leave_period.value) {
 							me.set_effective_date();
 						}
-					}
+					},
+					get_query() {
+						let filters = {"is_active": 1};
+						if (cur_dialog.fields_dict.company.value)
+							filters["company"] = cur_dialog.fields_dict.company.value;
+
+						return {
+							filters: filters
+						};
+					},
 				},
 				{
 					fieldtype: "Column Break"
diff --git a/erpnext/manufacturing/doctype/work_order/test_work_order.py b/erpnext/manufacturing/doctype/work_order/test_work_order.py
index 9926b15..e7eb9c6 100644
--- a/erpnext/manufacturing/doctype/work_order/test_work_order.py
+++ b/erpnext/manufacturing/doctype/work_order/test_work_order.py
@@ -2,7 +2,7 @@
 # License: GNU General Public License v3. See license.txt
 
 import frappe
-from frappe.utils import add_months, cint, flt, now, today
+from frappe.utils import add_days, add_months, cint, flt, now, today
 
 from erpnext.manufacturing.doctype.job_card.job_card import JobCardCancelError
 from erpnext.manufacturing.doctype.production_plan.test_production_plan import make_bom
@@ -12,6 +12,7 @@
 	OverProductionError,
 	StockOverProductionError,
 	close_work_order,
+	make_job_card,
 	make_stock_entry,
 	stop_unstop,
 )
@@ -804,6 +805,34 @@
 			if row.is_scrap_item:
 				self.assertEqual(row.qty, 1)
 
+		# Partial Job Card 1 with qty 10
+		wo_order = make_wo_order_test_record(item=item, company=company, planned_start_date=add_days(now(), 60), qty=20, skip_transfer=1)
+		job_card = frappe.db.get_value('Job Card', {'work_order': wo_order.name}, 'name')
+		update_job_card(job_card, 10)
+
+		stock_entry = frappe.get_doc(make_stock_entry(wo_order.name, "Manufacture", 10))
+		for row in stock_entry.items:
+			if row.is_scrap_item:
+				self.assertEqual(row.qty, 2)
+
+		# Partial Job Card 2 with qty 10
+		operations = []
+		wo_order.load_from_db()
+		for row in wo_order.operations:
+			n_dict = row.as_dict()
+			n_dict['qty'] = 10
+			n_dict['pending_qty'] = 10
+			operations.append(n_dict)
+
+		make_job_card(wo_order.name, operations)
+		job_card = frappe.db.get_value('Job Card', {'work_order': wo_order.name, 'docstatus': 0}, 'name')
+		update_job_card(job_card, 10)
+
+		stock_entry = frappe.get_doc(make_stock_entry(wo_order.name, "Manufacture", 10))
+		for row in stock_entry.items:
+			if row.is_scrap_item:
+				self.assertEqual(row.qty, 2)
+
 	def test_close_work_order(self):
 		items = ['Test FG Item for Closed WO', 'Test RM Item 1 for Closed WO',
 			'Test RM Item 2 for Closed WO']
@@ -883,7 +912,8 @@
 		self.assertEqual(wo1.operations[0].time_in_mins, wo2.operations[0].time_in_mins)
 
 
-def update_job_card(job_card):
+def update_job_card(job_card, jc_qty=None):
+	employee = frappe.db.get_value('Employee', {'status': 'Active'}, 'name')
 	job_card_doc = frappe.get_doc('Job Card', job_card)
 	job_card_doc.set('scrap_items', [
 		{
@@ -896,8 +926,12 @@
 		},
 	])
 
+	if jc_qty:
+		job_card_doc.for_quantity = jc_qty
+
 	job_card_doc.append('time_logs', {
 		'from_time': now(),
+		'employee': employee,
 		'time_in_mins': 60,
 		'completed_qty': job_card_doc.for_quantity
 	})
diff --git a/erpnext/patches.txt b/erpnext/patches.txt
index 821a493..5190f9f 100644
--- a/erpnext/patches.txt
+++ b/erpnext/patches.txt
@@ -305,6 +305,7 @@
 erpnext.patches.v13_0.enable_scheduler_job_for_item_reposting
 erpnext.patches.v13_0.requeue_failed_reposts
 erpnext.patches.v13_0.update_job_card_status
+erpnext.patches.v13_0.enable_uoms
 erpnext.patches.v12_0.update_production_plan_status
 erpnext.patches.v13_0.healthcare_deprecation_warning
 erpnext.patches.v13_0.item_naming_series_not_mandatory
diff --git a/erpnext/patches/v13_0/enable_uoms.py b/erpnext/patches/v13_0/enable_uoms.py
new file mode 100644
index 0000000..4d3f637
--- /dev/null
+++ b/erpnext/patches/v13_0/enable_uoms.py
@@ -0,0 +1,13 @@
+import frappe
+
+
+def execute():
+	frappe.reload_doc('setup', 'doctype', 'uom')
+
+	uom = frappe.qb.DocType("UOM")
+
+	(frappe.qb
+		.update(uom)
+		.set(uom.enabled, 1)
+		.where(uom.creation >= "2021-10-18")  # date when this field was released
+	).run()
diff --git a/erpnext/patches/v14_0/delete_healthcare_doctypes.py b/erpnext/patches/v14_0/delete_healthcare_doctypes.py
index 28fc01b..3a4f8f5 100644
--- a/erpnext/patches/v14_0/delete_healthcare_doctypes.py
+++ b/erpnext/patches/v14_0/delete_healthcare_doctypes.py
@@ -47,3 +47,18 @@
 		frappe.delete_doc("DocType", doctype, ignore_missing=True)
 
 	frappe.delete_doc("Module Def", "Healthcare", ignore_missing=True, force=True)
+
+	custom_fields = {
+		'Sales Invoice': ['patient', 'patient_name', 'ref_practitioner'],
+		'Sales Invoice Item': ['reference_dt', 'reference_dn'],
+		'Stock Entry': ['inpatient_medication_entry'],
+		'Stock Entry Detail': ['patient', 'inpatient_medication_entry_child'],
+	}
+	for doc, fields in custom_fields.items():
+		filters = {
+			'dt': doc,
+			'fieldname': ['in', fields]
+		}
+		records = frappe.get_all('Custom Field', filters=filters, pluck='name')
+		for record in records:
+			frappe.delete_doc('Custom Field', record, ignore_missing=True, force=True)
diff --git a/erpnext/payroll/doctype/payroll_entry/payroll_entry.py b/erpnext/payroll/doctype/payroll_entry/payroll_entry.py
index ed3fa5b..db88c06 100644
--- a/erpnext/payroll/doctype/payroll_entry/payroll_entry.py
+++ b/erpnext/payroll/doctype/payroll_entry/payroll_entry.py
@@ -61,6 +61,8 @@
 	def on_cancel(self):
 		frappe.delete_doc("Salary Slip", frappe.db.sql_list("""select name from `tabSalary Slip`
 			where payroll_entry=%s """, (self.name)))
+		self.db_set("salary_slips_created", 0)
+		self.db_set("salary_slips_submitted", 0)
 
 	def get_emp_list(self):
 		"""
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 0c0acc7..b2bf546 100644
--- a/erpnext/selling/report/sales_order_analysis/sales_order_analysis.py
+++ b/erpnext/selling/report/sales_order_analysis/sales_order_analysis.py
@@ -68,7 +68,8 @@
 			(soi.billed_amt * IFNULL(so.conversion_rate, 1)) as billed_amount,
 			(soi.base_amount - (soi.billed_amt * IFNULL(so.conversion_rate, 1))) as pending_amount,
 			soi.warehouse as warehouse,
-			so.company, soi.name
+			so.company, soi.name,
+			soi.description as description
 		FROM
 			`tabSales Order` so,
 			(`tabSales Order Item` soi
@@ -184,6 +185,12 @@
 			"options": "Item",
 			"width": 100
 		})
+		columns.append({
+			"label":_("Description"),
+			"fieldname": "description",
+			"fieldtype": "Small Text",
+			"width": 100
+		})
 
 	columns.extend([
 		{
diff --git a/erpnext/setup/doctype/company/company.js b/erpnext/setup/doctype/company/company.js
index 45e8dcc..dd185fc 100644
--- a/erpnext/setup/doctype/company/company.js
+++ b/erpnext/setup/doctype/company/company.js
@@ -213,6 +213,9 @@
 		["default_payroll_payable_account", {"root_type": "Liability"}],
 		["round_off_account", {"root_type": "Expense"}],
 		["write_off_account", {"root_type": "Expense"}],
+		["default_deferred_expense_account", {}],
+		["default_deferred_revenue_account", {}],
+		["default_expense_claim_payable_account", {}],
 		["default_discount_account", {}],
 		["discount_allowed_account", {"root_type": "Expense"}],
 		["discount_received_account", {"root_type": "Income"}],
diff --git a/erpnext/setup/setup_wizard/operations/install_fixtures.py b/erpnext/setup/setup_wizard/operations/install_fixtures.py
index 336b51c..9dbf49e 100644
--- a/erpnext/setup/setup_wizard/operations/install_fixtures.py
+++ b/erpnext/setup/setup_wizard/operations/install_fixtures.py
@@ -353,7 +353,8 @@
 				"doctype": "UOM",
 				"uom_name": _(d.get("uom_name")),
 				"name": _(d.get("uom_name")),
-				"must_be_whole_number": d.get("must_be_whole_number")
+				"must_be_whole_number": d.get("must_be_whole_number"),
+				"enabled": 1,
 			}).db_insert()
 
 	# bootstrap uom conversion factors
diff --git a/erpnext/stock/doctype/item/item.py b/erpnext/stock/doctype/item/item.py
index decf522..281e881 100644
--- a/erpnext/stock/doctype/item/item.py
+++ b/erpnext/stock/doctype/item/item.py
@@ -492,18 +492,20 @@
 		context.shopping_cart = get_product_info_for_website(self.name, skip_quotation_creation=True)
 
 	def add_default_uom_in_conversion_factor_table(self):
-		uom_conv_list = [d.uom for d in self.get("uoms")]
-		if self.stock_uom not in uom_conv_list:
-			ch = self.append('uoms', {})
-			ch.uom = self.stock_uom
-			ch.conversion_factor = 1
+		if not self.is_new() and self.has_value_changed("stock_uom"):
+			self.uoms = []
+			frappe.msgprint(
+				_("Successfully changed Stock UOM, please redefine conversion factors for new UOM."),
+				alert=True,
+			)
 
-		to_remove = []
-		for d in self.get("uoms"):
-			if d.conversion_factor == 1 and d.uom != self.stock_uom:
-				to_remove.append(d)
+		uoms_list = [d.uom for d in self.get("uoms")]
 
-		[self.remove(d) for d in to_remove]
+		if self.stock_uom not in uoms_list:
+			self.append("uoms", {
+				"uom": self.stock_uom,
+				"conversion_factor": 1
+			})
 
 	def update_show_in_website(self):
 		if self.disabled:
diff --git a/erpnext/stock/doctype/item/test_item.py b/erpnext/stock/doctype/item/test_item.py
index 4028d93..0957ce0 100644
--- a/erpnext/stock/doctype/item/test_item.py
+++ b/erpnext/stock/doctype/item/test_item.py
@@ -584,6 +584,16 @@
 		except frappe.ValidationError as e:
 			self.fail(f"UoM change not allowed even though no SLE / BIN with positive qty exists: {e}")
 
+	def test_erasure_of_old_conversions(self):
+		item = create_item("_item change uom")
+		item.stock_uom = "Gram"
+		item.append("uoms", frappe._dict(uom="Box", conversion_factor=2))
+		item.save()
+		item.reload()
+		item.stock_uom = "Nos"
+		item.save()
+		self.assertEqual(len(item.uoms), 1)
+
 	def test_validate_stock_item(self):
 		self.assertRaises(frappe.ValidationError, validate_is_stock_item, "_Test Non Stock Item")
 
diff --git a/erpnext/stock/doctype/stock_entry/stock_entry.py b/erpnext/stock/doctype/stock_entry/stock_entry.py
index 93e303c..a61b319 100644
--- a/erpnext/stock/doctype/stock_entry/stock_entry.py
+++ b/erpnext/stock/doctype/stock_entry/stock_entry.py
@@ -8,6 +8,7 @@
 import frappe
 from frappe import _
 from frappe.model.mapper import get_mapped_doc
+from frappe.query_builder.functions import Sum
 from frappe.utils import cint, comma_or, cstr, flt, format_time, formatdate, getdate, nowdate
 
 import erpnext
@@ -85,8 +86,11 @@
 		self.validate_warehouse()
 		self.validate_work_order()
 		self.validate_bom()
-		self.mark_finished_and_scrap_items()
-		self.validate_finished_goods()
+
+		if self.purpose in ("Manufacture", "Repack"):
+			self.mark_finished_and_scrap_items()
+			self.validate_finished_goods()
+
 		self.validate_with_material_request()
 		self.validate_batch()
 		self.validate_inspection()
@@ -109,8 +113,12 @@
 		self.set_actual_qty()
 		self.calculate_rate_and_amount()
 		self.validate_putaway_capacity()
-		self.reset_default_field_value("from_warehouse", "items", "s_warehouse")
-		self.reset_default_field_value("to_warehouse", "items", "t_warehouse")
+
+		if not self.get("purpose") == "Manufacture":
+			# ignore scrap item wh difference and empty source/target wh
+			# in Manufacture Entry
+			self.reset_default_field_value("from_warehouse", "items", "s_warehouse")
+			self.reset_default_field_value("to_warehouse", "items", "t_warehouse")
 
 	def on_submit(self):
 		self.update_stock_ledger()
@@ -701,26 +709,25 @@
 				validate_bom_no(item_code, d.bom_no)
 
 	def mark_finished_and_scrap_items(self):
-		if self.purpose in ("Repack", "Manufacture"):
-			if any([d.item_code for d in self.items if (d.is_finished_item and d.t_warehouse)]):
-				return
+		if any([d.item_code for d in self.items if (d.is_finished_item and d.t_warehouse)]):
+			return
 
-			finished_item = self.get_finished_item()
+		finished_item = self.get_finished_item()
 
-			if not finished_item and self.purpose == "Manufacture":
-				# In case of independent Manufacture entry, don't auto set
-				# user must decide and set
-				return
+		if not finished_item and self.purpose == "Manufacture":
+			# In case of independent Manufacture entry, don't auto set
+			# user must decide and set
+			return
 
-			for d in self.items:
-				if d.t_warehouse and not d.s_warehouse:
-					if self.purpose=="Repack" or d.item_code == finished_item:
-						d.is_finished_item = 1
-					else:
-						d.is_scrap_item = 1
+		for d in self.items:
+			if d.t_warehouse and not d.s_warehouse:
+				if self.purpose=="Repack" or d.item_code == finished_item:
+					d.is_finished_item = 1
 				else:
-					d.is_finished_item = 0
-					d.is_scrap_item = 0
+					d.is_scrap_item = 1
+			else:
+				d.is_finished_item = 0
+				d.is_scrap_item = 0
 
 	def get_finished_item(self):
 		finished_item = None
@@ -733,9 +740,9 @@
 
 	def validate_finished_goods(self):
 		"""
-			1. Check if FG exists
-			2. Check if Multiple FG Items are present
-			3. Check FG Item and Qty against WO if present
+			1. Check if FG exists (mfg, repack)
+			2. Check if Multiple FG Items are present (mfg)
+			3. Check FG Item and Qty against WO if present (mfg)
 		"""
 		production_item, wo_qty, finished_items = None, 0, []
 
@@ -748,8 +755,9 @@
 		for d in self.get('items'):
 			if d.is_finished_item:
 				if not self.work_order:
+					# Independent MFG Entry/ Repack Entry, no WO to match against
 					finished_items.append(d.item_code)
-					continue # Independent Manufacture Entry, no WO to match against
+					continue
 
 				if d.item_code != production_item:
 					frappe.throw(_("Finished Item {0} does not match with Work Order {1}")
@@ -762,19 +770,17 @@
 
 				finished_items.append(d.item_code)
 
-		if len(set(finished_items)) > 1:
+		if not finished_items:
 			frappe.throw(
-				msg=_("Multiple items cannot be marked as finished item"),
-				title=_("Note"),
-				exc=FinishedGoodError
+				msg=_("There must be atleast 1 Finished Good in this Stock Entry").format(self.name),
+				title=_("Missing Finished Good"), exc=FinishedGoodError
 			)
 
 		if self.purpose == "Manufacture":
-			if not finished_items:
+			if len(set(finished_items)) > 1:
 				frappe.throw(
-					msg=_("There must be atleast 1 Finished Good in this Stock Entry").format(self.name),
-					title=_("Missing Finished Good"),
-					exc=FinishedGoodError
+					msg=_("Multiple items cannot be marked as finished item"),
+					title=_("Note"), exc=FinishedGoodError
 				)
 
 			allowance_percentage = flt(
@@ -1275,22 +1281,29 @@
 		if not self.pro_doc:
 			self.set_work_order_details()
 
-		scrap_items = frappe.db.sql('''
-			SELECT
-				JCSI.item_code, JCSI.item_name, SUM(JCSI.stock_qty) as stock_qty, JCSI.stock_uom, JCSI.description
-			FROM
-				`tabJob Card` JC, `tabJob Card Scrap Item` JCSI
-			WHERE
-				JCSI.parent = JC.name AND JC.docstatus = 1
-				AND JCSI.item_code IS NOT NULL AND JC.work_order = %s
-			GROUP BY
-				JCSI.item_code
-		''', self.work_order, as_dict=1)
-
-		pending_qty = flt(self.pro_doc.qty) - flt(self.pro_doc.produced_qty)
-		if pending_qty <=0:
+		if not self.pro_doc.operations:
 			return []
 
+		job_card = frappe.qb.DocType('Job Card')
+		job_card_scrap_item = frappe.qb.DocType('Job Card Scrap Item')
+
+		scrap_items = (
+			frappe.qb.from_(job_card)
+			.select(
+				Sum(job_card_scrap_item.stock_qty).as_('stock_qty'),
+				job_card_scrap_item.item_code, job_card_scrap_item.item_name,
+				job_card_scrap_item.description, job_card_scrap_item.stock_uom)
+			.join(job_card_scrap_item)
+			.on(job_card_scrap_item.parent == job_card.name)
+			.where(
+				(job_card_scrap_item.item_code.isnotnull())
+				& (job_card.work_order == self.work_order)
+				& (job_card.docstatus == 1))
+			.groupby(job_card_scrap_item.item_code)
+		).run(as_dict=1)
+
+		pending_qty = flt(self.get_completed_job_card_qty()) - flt(self.pro_doc.produced_qty)
+
 		used_scrap_items = self.get_used_scrap_items()
 		for row in scrap_items:
 			row.stock_qty -= flt(used_scrap_items.get(row.item_code))
@@ -1304,6 +1317,9 @@
 
 		return scrap_items
 
+	def get_completed_job_card_qty(self):
+		return flt(min([d.completed_qty for d in self.pro_doc.operations]))
+
 	def get_used_scrap_items(self):
 		used_scrap_items = defaultdict(float)
 		data = frappe.get_all(
diff --git a/erpnext/stock/doctype/stock_entry/test_stock_entry.py b/erpnext/stock/doctype/stock_entry/test_stock_entry.py
index b874874..8f5d442 100644
--- a/erpnext/stock/doctype/stock_entry/test_stock_entry.py
+++ b/erpnext/stock/doctype/stock_entry/test_stock_entry.py
@@ -226,9 +226,47 @@
 
 		mtn.cancel()
 
-	def test_repack_no_change_in_valuation(self):
-		company = frappe.db.get_value('Warehouse', '_Test Warehouse - _TC', 'company')
+	def test_repack_multiple_fg(self):
+		"Test `is_finished_item` for one item repacked into two items."
+		make_stock_entry(item_code="_Test Item", target="_Test Warehouse - _TC", qty=100, basic_rate=100)
 
+		repack = frappe.copy_doc(test_records[3])
+		repack.posting_date = nowdate()
+		repack.posting_time = nowtime()
+
+		repack.items[0].qty = 100.0
+		repack.items[0].transfer_qty = 100.0
+		repack.items[1].qty = 50.0
+
+		repack.append("items", {
+			"conversion_factor": 1.0,
+			"cost_center": "_Test Cost Center - _TC",
+			"doctype": "Stock Entry Detail",
+			"expense_account": "Stock Adjustment - _TC",
+			"basic_rate": 150,
+			"item_code": "_Test Item 2",
+			"parentfield": "items",
+			"qty": 50.0,
+			"stock_uom": "_Test UOM",
+			"t_warehouse": "_Test Warehouse - _TC",
+			"transfer_qty": 50.0,
+			"uom": "_Test UOM"
+		})
+		repack.set_stock_entry_type()
+		repack.insert()
+
+		self.assertEqual(repack.items[1].is_finished_item, 1)
+		self.assertEqual(repack.items[2].is_finished_item, 1)
+
+		repack.items[1].is_finished_item = 0
+		repack.items[2].is_finished_item = 0
+
+		# must raise error if 0 fg in repack entry
+		self.assertRaises(FinishedGoodError, repack.validate_finished_goods)
+
+		repack.delete() # teardown
+
+	def test_repack_no_change_in_valuation(self):
 		make_stock_entry(item_code="_Test Item", target="_Test Warehouse - _TC", qty=50, basic_rate=100)
 		make_stock_entry(item_code="_Test Item Home Desktop 100", target="_Test Warehouse - _TC",
 			qty=50, basic_rate=100)
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 b3348f1..ea617fd 100644
--- a/erpnext/support/doctype/service_level_agreement/service_level_agreement.py
+++ b/erpnext/support/doctype/service_level_agreement/service_level_agreement.py
@@ -853,7 +853,7 @@
 @frappe.whitelist()
 def get_sla_doctypes():
 	doctypes = []
-	data = frappe.get_list('Service Level Agreement',
+	data = frappe.get_all('Service Level Agreement',
 		{'enabled': 1},
 		['document_type'],
 		distinct=1
diff --git a/erpnext/utilities/transaction_base.py b/erpnext/utilities/transaction_base.py
index 1d8b3a8..feea228 100644
--- a/erpnext/utilities/transaction_base.py
+++ b/erpnext/utilities/transaction_base.py
@@ -181,8 +181,6 @@
 
 		if len(child_table_values) > 1:
 			self.set(default_field, None)
-		else:
-			self.set(default_field, list(child_table_values)[0])
 
 def delete_events(ref_type, ref_name):
 	events = frappe.db.sql_list(""" SELECT