Merge pull request #30160 from marination/cart-without-checkout

fix: 'save_quotations_as_draft' checkbox not honoured
diff --git a/erpnext/accounts/party.py b/erpnext/accounts/party.py
index d6f6c5b..791cd1d 100644
--- a/erpnext/accounts/party.py
+++ b/erpnext/accounts/party.py
@@ -151,7 +151,7 @@
 
 def set_other_values(party_details, party, party_type):
 	# copy
-	if party_type=="Customer":
+	if party_type == "Customer":
 		to_copy = ["customer_name", "customer_group", "territory", "language"]
 	else:
 		to_copy = ["supplier_name", "supplier_group", "language"]
@@ -170,12 +170,8 @@
 		return party.default_price_list
 
 	if party.doctype == "Customer":
-		price_list =  frappe.get_cached_value("Customer Group",
-			party.customer_group, "default_price_list")
-		if price_list:
-			return price_list
+		return frappe.db.get_value("Customer Group", party.customer_group, "default_price_list")
 
-	return None
 
 def set_price_list(party_details, party, party_type, given_price_list, pos=None):
 	# price list
diff --git a/erpnext/accounts/test_party.py b/erpnext/accounts/test_party.py
new file mode 100644
index 0000000..f7a1a85
--- /dev/null
+++ b/erpnext/accounts/test_party.py
@@ -0,0 +1,16 @@
+import frappe
+from frappe.tests.utils import FrappeTestCase
+
+from erpnext.accounts.party import get_default_price_list
+
+
+class PartyTestCase(FrappeTestCase):
+	def test_get_default_price_list_should_return_none_for_invalid_group(self):
+		customer = frappe.get_doc({
+			'doctype': 'Customer',
+			'customer_name': 'test customer',
+		}).insert(ignore_permissions=True, ignore_mandatory=True)
+		customer.customer_group = None
+		customer.save()
+		price_list = get_default_price_list(customer)
+		assert price_list is None
diff --git a/erpnext/hr/doctype/attendance/test_attendance.py b/erpnext/hr/doctype/attendance/test_attendance.py
index c74967d..6095413 100644
--- a/erpnext/hr/doctype/attendance/test_attendance.py
+++ b/erpnext/hr/doctype/attendance/test_attendance.py
@@ -25,7 +25,9 @@
 		self.assertEqual(attendance, fetch_attendance)
 
 	def test_unmarked_days(self):
-		first_day = get_first_day(getdate())
+		now = now_datetime()
+		previous_month = now.month - 1
+		first_day = now.replace(day=1).replace(month=previous_month).date()
 
 		employee = make_employee('test_unmarked_days@example.com', date_of_joining=add_days(first_day, -1))
 		frappe.db.delete('Attendance', {'employee': employee})
@@ -34,7 +36,7 @@
 		holiday_list = make_holiday_list()
 		frappe.db.set_value('Employee', employee, 'holiday_list', holiday_list)
 
-		first_sunday = get_first_sunday(holiday_list)
+		first_sunday = get_first_sunday(holiday_list, for_date=first_day)
 		mark_attendance(employee, first_day, 'Present')
 		month_name = get_month_name(first_day)
 
@@ -49,7 +51,9 @@
 		self.assertIn(first_sunday, unmarked_days)
 
 	def test_unmarked_days_excluding_holidays(self):
-		first_day = get_first_day(getdate())
+		now = now_datetime()
+		previous_month = now.month - 1
+		first_day = now.replace(day=1).replace(month=previous_month).date()
 
 		employee = make_employee('test_unmarked_days@example.com', date_of_joining=add_days(first_day, -1))
 		frappe.db.delete('Attendance', {'employee': employee})
@@ -58,7 +62,7 @@
 		holiday_list = make_holiday_list()
 		frappe.db.set_value('Employee', employee, 'holiday_list', holiday_list)
 
-		first_sunday = get_first_sunday(holiday_list)
+		first_sunday = get_first_sunday(holiday_list, for_date=first_day)
 		mark_attendance(employee, first_day, 'Present')
 		month_name = get_month_name(first_day)
 
@@ -83,6 +87,10 @@
 			relieving_date=relieving_date)
 		frappe.db.delete('Attendance', {'employee': employee})
 
+		from erpnext.payroll.doctype.salary_slip.test_salary_slip import make_holiday_list
+		holiday_list = make_holiday_list()
+		frappe.db.set_value('Employee', employee, 'holiday_list', holiday_list)
+
 		attendance_date = add_days(first_day, 2)
 		mark_attendance(employee, attendance_date, 'Present')
 		month_name = get_month_name(first_day)
diff --git a/erpnext/hr/doctype/leave_application/test_leave_application.py b/erpnext/hr/doctype/leave_application/test_leave_application.py
index 7b3aa49..01e0ca0 100644
--- a/erpnext/hr/doctype/leave_application/test_leave_application.py
+++ b/erpnext/hr/doctype/leave_application/test_leave_application.py
@@ -133,7 +133,9 @@
 
 		holiday_list = make_holiday_list()
 		employee = get_employee()
-		frappe.db.set_value("Company", employee.company, "default_holiday_list", holiday_list)
+		original_holiday_list = employee.holiday_list
+		frappe.db.set_value("Employee", employee.name, "holiday_list", holiday_list)
+
 		first_sunday = get_first_sunday(holiday_list)
 
 		leave_application = make_leave_application(employee.name, first_sunday, add_days(first_sunday, 3), leave_type.name)
@@ -143,6 +145,8 @@
 
 		leave_application.cancel()
 
+		frappe.db.set_value("Employee", employee.name, "holiday_list", original_holiday_list)
+
 	def test_attendance_update_for_exclude_holidays(self):
 		# Case 2: leave type with 'Include holidays within leaves as leaves' disabled
 		frappe.delete_doc_if_exists("Leave Type", "Test Do Not Include Holidays", force=1)
@@ -157,7 +161,8 @@
 
 		holiday_list = make_holiday_list()
 		employee = get_employee()
-		frappe.db.set_value("Company", employee.company, "default_holiday_list", holiday_list)
+		original_holiday_list = employee.holiday_list
+		frappe.db.set_value("Employee", employee.name, "holiday_list", holiday_list)
 		first_sunday = get_first_sunday(holiday_list)
 
 		# already marked attendance on a holiday should be deleted in this case
@@ -177,7 +182,7 @@
 		attendance.flags.ignore_validate = True
 		attendance.save()
 
-		leave_application = make_leave_application(employee.name, first_sunday, add_days(first_sunday, 3), leave_type.name)
+		leave_application = make_leave_application(employee.name, first_sunday, add_days(first_sunday, 3), leave_type.name, employee.company)
 		leave_application.reload()
 		# holiday should be excluded while marking attendance
 		self.assertEqual(leave_application.total_leave_days, 3)
@@ -189,6 +194,8 @@
 		# attendance on non-holiday updated
 		self.assertEqual(frappe.db.get_value("Attendance", attendance.name, "status"), "On Leave")
 
+		frappe.db.set_value("Employee", employee.name, "holiday_list", original_holiday_list)
+
 	def test_block_list(self):
 		self._clear_roles()
 
@@ -327,7 +334,8 @@
 		employee = get_employee()
 
 		default_holiday_list = make_holiday_list()
-		frappe.db.set_value("Company", employee.company, "default_holiday_list", default_holiday_list)
+		original_holiday_list = employee.holiday_list
+		frappe.db.set_value("Employee", employee.name, "holiday_list", default_holiday_list)
 		first_sunday = get_first_sunday(default_holiday_list)
 
 		optional_leave_date = add_days(first_sunday, 1)
@@ -378,6 +386,8 @@
 		# check leave balance is reduced
 		self.assertEqual(get_leave_balance_on(employee.name, leave_type, optional_leave_date), 9)
 
+		frappe.db.set_value("Employee", employee.name, "holiday_list", original_holiday_list)
+
 	def test_leaves_allowed(self):
 		employee = get_employee()
 		leave_period = get_leave_period()
@@ -782,9 +792,10 @@
 	allocate_leave.submit()
 
 
-def get_first_sunday(holiday_list):
-	month_start_date = get_first_day(nowdate())
-	month_end_date = get_last_day(nowdate())
+def get_first_sunday(holiday_list, for_date=None):
+	date = for_date or getdate()
+	month_start_date = get_first_day(date)
+	month_end_date = get_last_day(date)
 	first_sunday = frappe.db.sql("""
 		select holiday_date from `tabHoliday`
 		where parent = %s
diff --git a/erpnext/stock/doctype/item/item.js b/erpnext/stock/doctype/item/item.js
index ffea9c2..9e8b3bd 100644
--- a/erpnext/stock/doctype/item/item.js
+++ b/erpnext/stock/doctype/item/item.js
@@ -165,21 +165,21 @@
 		frm.set_value('has_batch_no', 0);
 		frm.toggle_enable(['has_serial_no', 'serial_no_series'], !frm.doc.is_fixed_asset);
 
-		frm.call({
-			method: "set_asset_naming_series",
-			doc: frm.doc,
-			callback: function() {
+		frappe.call({
+			method: "erpnext.stock.doctype.item.item.get_asset_naming_series",
+			callback: function(r) {
 				frm.set_value("is_stock_item", frm.doc.is_fixed_asset ? 0 : 1);
-				frm.trigger("set_asset_naming_series");
+				frm.events.set_asset_naming_series(frm, r.message);
 			}
 		});
 
 		frm.trigger('auto_create_assets');
 	},
 
-	set_asset_naming_series: function(frm) {
-		if (frm.doc.__onload && frm.doc.__onload.asset_naming_series) {
-			frm.set_df_property("asset_naming_series", "options", frm.doc.__onload.asset_naming_series);
+	set_asset_naming_series: function(frm, asset_naming_series) {
+		if ((frm.doc.__onload && frm.doc.__onload.asset_naming_series) || asset_naming_series) {
+			let naming_series = (frm.doc.__onload && frm.doc.__onload.asset_naming_series) || asset_naming_series;
+			frm.set_df_property("asset_naming_series", "options", naming_series);
 		}
 	},
 
diff --git a/erpnext/stock/doctype/item/item.py b/erpnext/stock/doctype/item/item.py
index 494fb3b..32c72fd 100644
--- a/erpnext/stock/doctype/item/item.py
+++ b/erpnext/stock/doctype/item/item.py
@@ -50,15 +50,7 @@
 class Item(Document):
 	def onload(self):
 		self.set_onload('stock_exists', self.stock_ledger_created())
-		self.set_asset_naming_series()
-
-	@frappe.whitelist()
-	def set_asset_naming_series(self):
-		if not hasattr(self, '_asset_naming_series'):
-			from erpnext.assets.doctype.asset.asset import get_asset_naming_series
-			self._asset_naming_series = get_asset_naming_series()
-
-		self.set_onload('asset_naming_series', self._asset_naming_series)
+		self.set_onload('asset_naming_series', get_asset_naming_series())
 
 	def autoname(self):
 		if frappe.db.get_default("item_naming_by") == "Naming Series":
@@ -999,7 +991,7 @@
 	if uom == stock_uom:
 		return 1.0
 
-	from_uom, to_uom = uom, stock_uom   # renaming for readability
+	from_uom, to_uom = uom, stock_uom	# renaming for readability
 
 	exact_match = frappe.db.get_value("UOM Conversion Factor", {"to_uom": to_uom, "from_uom": from_uom}, ["value"], as_dict=1)
 	if exact_match:
@@ -1011,9 +1003,9 @@
 
 	# This attempts to try and get conversion from intermediate UOM.
 	# case:
-	#            g -> mg = 1000
-	#            g -> kg = 0.001
-	# therefore  kg -> mg = 1000  / 0.001 = 1,000,000
+	#			 g -> mg = 1000
+	#			 g -> kg = 0.001
+	# therefore	 kg -> mg = 1000  / 0.001 = 1,000,000
 	intermediate_match = frappe.db.sql("""
 			select (first.value / second.value) as value
 			from `tabUOM Conversion Factor` first
@@ -1072,3 +1064,11 @@
 							frappe.bold(item_default.company),
 							frappe.bold(frappe.unscrub(field))
 						), title=_("Invalid Item Defaults"))
+
+
+@frappe.whitelist()
+def get_asset_naming_series():
+	from erpnext.assets.doctype.asset.asset import get_asset_naming_series
+
+	return get_asset_naming_series()
+