Merge pull request #33422 from rohitwaghchaure/fix-stock-entry-submit-performance

fix: timeout error while submitting stock entry
diff --git a/erpnext/accounts/doctype/payment_entry/payment_entry.py b/erpnext/accounts/doctype/payment_entry/payment_entry.py
index 4be4764..79fab64 100644
--- a/erpnext/accounts/doctype/payment_entry/payment_entry.py
+++ b/erpnext/accounts/doctype/payment_entry/payment_entry.py
@@ -1640,7 +1640,7 @@
 ):
 	reference_doc = None
 	doc = frappe.get_doc(dt, dn)
-	if dt in ("Sales Order", "Purchase Order") and flt(doc.per_billed, 2) > 0:
+	if dt in ("Sales Order", "Purchase Order") and flt(doc.per_billed, 2) >= 99.99:
 		frappe.throw(_("Can only make payment against unbilled {0}").format(dt))
 
 	if not party_type:
diff --git a/erpnext/accounts/doctype/payment_request/payment_request.js b/erpnext/accounts/doctype/payment_request/payment_request.js
index 901ef19..e913912 100644
--- a/erpnext/accounts/doctype/payment_request/payment_request.js
+++ b/erpnext/accounts/doctype/payment_request/payment_request.js
@@ -42,7 +42,7 @@
 		});
 	}
 
-	if(!frm.doc.payment_gateway_account && frm.doc.status == "Initiated") {
+	if((!frm.doc.payment_gateway_account || frm.doc.payment_request_type == "Outward") && frm.doc.status == "Initiated") {
 		frm.add_custom_button(__('Create Payment Entry'), function(){
 			frappe.call({
 				method: "erpnext.accounts.doctype.payment_request.payment_request.make_payment_entry",
diff --git a/erpnext/accounts/doctype/payment_request/payment_request.py b/erpnext/accounts/doctype/payment_request/payment_request.py
index d82083c..fc93801 100644
--- a/erpnext/accounts/doctype/payment_request/payment_request.py
+++ b/erpnext/accounts/doctype/payment_request/payment_request.py
@@ -261,6 +261,7 @@
 
 		payment_entry.update(
 			{
+				"mode_of_payment": self.mode_of_payment,
 				"reference_no": self.name,
 				"reference_date": nowdate(),
 				"remarks": "Payment Entry against {0} {1} via Payment Request {2}".format(
@@ -410,25 +411,22 @@
 		else ""
 	)
 
-	existing_payment_request = None
-	if args.order_type == "Shopping Cart":
-		existing_payment_request = frappe.db.get_value(
-			"Payment Request",
-			{"reference_doctype": args.dt, "reference_name": args.dn, "docstatus": ("!=", 2)},
-		)
+	draft_payment_request = frappe.db.get_value(
+		"Payment Request",
+		{"reference_doctype": args.dt, "reference_name": args.dn, "docstatus": 0},
+	)
 
-	if existing_payment_request:
+	existing_payment_request_amount = get_existing_payment_request_amount(args.dt, args.dn)
+
+	if existing_payment_request_amount:
+		grand_total -= existing_payment_request_amount
+
+	if draft_payment_request:
 		frappe.db.set_value(
-			"Payment Request", existing_payment_request, "grand_total", grand_total, update_modified=False
+			"Payment Request", draft_payment_request, "grand_total", grand_total, update_modified=False
 		)
-		pr = frappe.get_doc("Payment Request", existing_payment_request)
+		pr = frappe.get_doc("Payment Request", draft_payment_request)
 	else:
-		if args.order_type != "Shopping Cart":
-			existing_payment_request_amount = get_existing_payment_request_amount(args.dt, args.dn)
-
-			if existing_payment_request_amount:
-				grand_total -= existing_payment_request_amount
-
 		pr = frappe.new_doc("Payment Request")
 		pr.update(
 			{
diff --git a/erpnext/accounts/report/accounts_receivable/accounts_receivable.py b/erpnext/accounts/report/accounts_receivable/accounts_receivable.py
index 9d96843..fb2e444 100755
--- a/erpnext/accounts/report/accounts_receivable/accounts_receivable.py
+++ b/erpnext/accounts/report/accounts_receivable/accounts_receivable.py
@@ -798,19 +798,19 @@
 
 		if self.filters.get("payment_terms_template"):
 			self.qb_selection_filter.append(
-				self.ple.party_isin(
-					qb.from_(self.customer).where(
-						self.customer.payment_terms == self.filters.get("payment_terms_template")
-					)
+				self.ple.party.isin(
+					qb.from_(self.customer)
+					.select(self.customer.name)
+					.where(self.customer.payment_terms == self.filters.get("payment_terms_template"))
 				)
 			)
 
 		if self.filters.get("sales_partner"):
 			self.qb_selection_filter.append(
-				self.ple.party_isin(
-					qb.from_(self.customer).where(
-						self.customer.default_sales_partner == self.filters.get("payment_terms_template")
-					)
+				self.ple.party.isin(
+					qb.from_(self.customer)
+					.select(self.customer.name)
+					.where(self.customer.default_sales_partner == self.filters.get("payment_terms_template"))
 				)
 			)
 
diff --git a/erpnext/accounts/report/cash_flow/cash_flow.py b/erpnext/accounts/report/cash_flow/cash_flow.py
index d4f2011..cb3c78a 100644
--- a/erpnext/accounts/report/cash_flow/cash_flow.py
+++ b/erpnext/accounts/report/cash_flow/cash_flow.py
@@ -8,6 +8,7 @@
 
 from erpnext.accounts.report.financial_statements import (
 	get_columns,
+	get_cost_centers_with_children,
 	get_data,
 	get_filtered_list_for_consolidated_report,
 	get_period_list,
@@ -160,10 +161,11 @@
 	total = 0
 	for period in period_list:
 		start_date = get_start_date(period, accumulated_values, company)
+		filters.start_date = start_date
+		filters.end_date = period["to_date"]
+		filters.account_type = account_type
 
-		amount = get_account_type_based_gl_data(
-			company, start_date, period["to_date"], account_type, filters
-		)
+		amount = get_account_type_based_gl_data(company, filters)
 
 		if amount and account_type == "Depreciation":
 			amount *= -1
@@ -175,7 +177,7 @@
 	return data
 
 
-def get_account_type_based_gl_data(company, start_date, end_date, account_type, filters=None):
+def get_account_type_based_gl_data(company, filters=None):
 	cond = ""
 	filters = frappe._dict(filters or {})
 
@@ -191,17 +193,21 @@
 			frappe.db.escape(cstr(filters.finance_book))
 		)
 
+	if filters.get("cost_center"):
+		filters.cost_center = get_cost_centers_with_children(filters.cost_center)
+		cond += " and cost_center in %(cost_center)s"
+
 	gl_sum = frappe.db.sql_list(
 		"""
 		select sum(credit) - sum(debit)
 		from `tabGL Entry`
-		where company=%s and posting_date >= %s and posting_date <= %s
+		where company=%(company)s and posting_date >= %(start_date)s and posting_date <= %(end_date)s
 			and voucher_type != 'Period Closing Voucher'
-			and account in ( SELECT name FROM tabAccount WHERE account_type = %s) {cond}
+			and account in ( SELECT name FROM tabAccount WHERE account_type = %(account_type)s) {cond}
 	""".format(
 			cond=cond
 		),
-		(company, start_date, end_date, account_type),
+		filters,
 	)
 
 	return gl_sum[0] if gl_sum and gl_sum[0] else 0
diff --git a/erpnext/accounts/report/consolidated_financial_statement/consolidated_financial_statement.py b/erpnext/accounts/report/consolidated_financial_statement/consolidated_financial_statement.py
index d269e1f..ddee9fc 100644
--- a/erpnext/accounts/report/consolidated_financial_statement/consolidated_financial_statement.py
+++ b/erpnext/accounts/report/consolidated_financial_statement/consolidated_financial_statement.py
@@ -268,10 +268,12 @@
 def get_account_type_based_data(account_type, companies, fiscal_year, filters):
 	data = {}
 	total = 0
+	filters.account_type = account_type
+	filters.start_date = fiscal_year.year_start_date
+	filters.end_date = fiscal_year.year_end_date
+
 	for company in companies:
-		amount = get_account_type_based_gl_data(
-			company, fiscal_year.year_start_date, fiscal_year.year_end_date, account_type, filters
-		)
+		amount = get_account_type_based_gl_data(company, filters)
 
 		if amount and account_type == "Depreciation":
 			amount *= -1
diff --git a/erpnext/accounts/report/gross_profit/gross_profit.py b/erpnext/accounts/report/gross_profit/gross_profit.py
index 99e86ae..8ba2310 100644
--- a/erpnext/accounts/report/gross_profit/gross_profit.py
+++ b/erpnext/accounts/report/gross_profit/gross_profit.py
@@ -607,6 +607,7 @@
 					return abs(previous_stock_value - flt(sle.stock_value)) * flt(row.qty) / abs(flt(sle.qty))
 				else:
 					return flt(row.qty) * self.get_average_buying_rate(row, item_code)
+		return 0.0
 
 	def get_buying_amount(self, row, item_code):
 		# IMP NOTE
diff --git a/erpnext/accounts/report/gross_profit/test_gross_profit.py b/erpnext/accounts/report/gross_profit/test_gross_profit.py
index 0ea6b5c..fa11a41 100644
--- a/erpnext/accounts/report/gross_profit/test_gross_profit.py
+++ b/erpnext/accounts/report/gross_profit/test_gross_profit.py
@@ -6,6 +6,8 @@
 from erpnext.accounts.doctype.sales_invoice.sales_invoice import make_delivery_note
 from erpnext.accounts.doctype.sales_invoice.test_sales_invoice import create_sales_invoice
 from erpnext.accounts.report.gross_profit.gross_profit import execute
+from erpnext.stock.doctype.delivery_note.delivery_note import make_sales_invoice
+from erpnext.stock.doctype.delivery_note.test_delivery_note import create_delivery_note
 from erpnext.stock.doctype.item.test_item import create_item
 from erpnext.stock.doctype.stock_entry.stock_entry_utils import make_stock_entry
 
@@ -14,6 +16,7 @@
 	def setUp(self):
 		self.create_company()
 		self.create_item()
+		self.create_bundle()
 		self.create_customer()
 		self.create_sales_invoice()
 		self.clear_old_entries()
@@ -42,6 +45,7 @@
 		self.company = company.name
 		self.cost_center = company.cost_center
 		self.warehouse = "Stores - " + abbr
+		self.finished_warehouse = "Finished Goods - " + abbr
 		self.income_account = "Sales - " + abbr
 		self.expense_account = "Cost of Goods Sold - " + abbr
 		self.debit_to = "Debtors - " + abbr
@@ -53,6 +57,23 @@
 		)
 		self.item = item if isinstance(item, str) else item.item_code
 
+	def create_bundle(self):
+		from erpnext.selling.doctype.product_bundle.test_product_bundle import make_product_bundle
+
+		item2 = create_item(
+			item_code="_Test GP Item 2", is_stock_item=1, company=self.company, warehouse=self.warehouse
+		)
+		self.item2 = item2 if isinstance(item2, str) else item2.item_code
+
+		# This will be parent item
+		bundle = create_item(
+			item_code="_Test GP bundle", is_stock_item=0, company=self.company, warehouse=self.warehouse
+		)
+		self.bundle = bundle if isinstance(bundle, str) else bundle.item_code
+
+		# Create Product Bundle
+		self.product_bundle = make_product_bundle(parent=self.bundle, items=[self.item, self.item2])
+
 	def create_customer(self):
 		name = "_Test GP Customer"
 		if frappe.db.exists("Customer", name):
@@ -93,6 +114,28 @@
 		)
 		return sinv
 
+	def create_delivery_note(
+		self, item=None, qty=1, rate=100, posting_date=nowdate(), do_not_save=False, do_not_submit=False
+	):
+		"""
+		Helper function to populate default values in Delivery Note
+		"""
+		dnote = create_delivery_note(
+			company=self.company,
+			customer=self.customer,
+			currency="INR",
+			item=item or self.item,
+			qty=qty,
+			rate=rate,
+			cost_center=self.cost_center,
+			warehouse=self.warehouse,
+			return_against=None,
+			expense_account=self.expense_account,
+			do_not_save=do_not_save,
+			do_not_submit=do_not_submit,
+		)
+		return dnote
+
 	def clear_old_entries(self):
 		doctype_list = [
 			"Sales Invoice",
@@ -207,3 +250,55 @@
 		}
 		gp_entry = [x for x in data if x.parent_invoice == sinv.name]
 		self.assertDictContainsSubset(expected_entry_with_dn, gp_entry[0])
+
+	def test_bundled_delivery_note_with_different_warehouses(self):
+		"""
+		Test Delivery Note with bundled item. Packed Item from the bundle having different warehouses
+		"""
+		se = make_stock_entry(
+			company=self.company,
+			item_code=self.item,
+			target=self.warehouse,
+			qty=1,
+			basic_rate=100,
+			do_not_submit=True,
+		)
+		item = se.items[0]
+		se.append(
+			"items",
+			{
+				"item_code": self.item2,
+				"s_warehouse": "",
+				"t_warehouse": self.finished_warehouse,
+				"qty": 1,
+				"basic_rate": 100,
+				"conversion_factor": item.conversion_factor or 1.0,
+				"transfer_qty": flt(item.qty) * (flt(item.conversion_factor) or 1.0),
+				"serial_no": item.serial_no,
+				"batch_no": item.batch_no,
+				"cost_center": item.cost_center,
+				"expense_account": item.expense_account,
+			},
+		)
+		se = se.save().submit()
+
+		# Make a Delivery note with Product bundle
+		# Packed Items will have different warehouses
+		dnote = self.create_delivery_note(item=self.bundle, qty=1, rate=200, do_not_submit=True)
+		dnote.packed_items[1].warehouse = self.finished_warehouse
+		dnote = dnote.submit()
+
+		# make Sales Invoice for above delivery note
+		sinv = make_sales_invoice(dnote.name)
+		sinv = sinv.save().submit()
+
+		filters = frappe._dict(
+			company=self.company,
+			from_date=nowdate(),
+			to_date=nowdate(),
+			group_by="Invoice",
+			sales_invoice=sinv.name,
+		)
+
+		columns, data = execute(filters=filters)
+		self.assertGreater(len(data), 0)
diff --git a/erpnext/buying/doctype/purchase_order/purchase_order.js b/erpnext/buying/doctype/purchase_order/purchase_order.js
index 06fdea0..47089f7 100644
--- a/erpnext/buying/doctype/purchase_order/purchase_order.js
+++ b/erpnext/buying/doctype/purchase_order/purchase_order.js
@@ -235,11 +235,11 @@
 						cur_frm.add_custom_button(__('Purchase Invoice'),
 							this.make_purchase_invoice, __('Create'));
 
-					if(flt(doc.per_billed)==0 && doc.status != "Delivered") {
+					if(flt(doc.per_billed) < 100 && doc.status != "Delivered") {
 						cur_frm.add_custom_button(__('Payment'), cur_frm.cscript.make_payment_entry, __('Create'));
 					}
 
-					if(flt(doc.per_billed)==0) {
+					if(flt(doc.per_billed) < 100) {
 						this.frm.add_custom_button(__('Payment Request'),
 							function() { me.make_payment_request() }, __('Create'));
 					}
diff --git a/erpnext/crm/doctype/appointment/appointment.json b/erpnext/crm/doctype/appointment/appointment.json
index fe7b4e1..c26b064 100644
--- a/erpnext/crm/doctype/appointment/appointment.json
+++ b/erpnext/crm/doctype/appointment/appointment.json
@@ -102,7 +102,7 @@
   }
  ],
  "links": [],
- "modified": "2021-06-30 13:09:14.228756",
+ "modified": "2022-12-15 11:11:02.131986",
  "modified_by": "Administrator",
  "module": "CRM",
  "name": "Appointment",
@@ -123,16 +123,6 @@
   },
   {
    "create": 1,
-   "email": 1,
-   "export": 1,
-   "print": 1,
-   "read": 1,
-   "report": 1,
-   "role": "Guest",
-   "share": 1
-  },
-  {
-   "create": 1,
    "delete": 1,
    "email": 1,
    "export": 1,
@@ -170,5 +160,6 @@
  "quick_entry": 1,
  "sort_field": "modified",
  "sort_order": "DESC",
+ "states": [],
  "track_changes": 1
 }
\ No newline at end of file
diff --git a/erpnext/crm/doctype/appointment/appointment.py b/erpnext/crm/doctype/appointment/appointment.py
index 6e7ba1f..bd49bdc 100644
--- a/erpnext/crm/doctype/appointment/appointment.py
+++ b/erpnext/crm/doctype/appointment/appointment.py
@@ -6,7 +6,9 @@
 
 import frappe
 from frappe import _
+from frappe.desk.form.assign_to import add as add_assignment
 from frappe.model.document import Document
+from frappe.share import add_docshare
 from frappe.utils import get_url, getdate, now
 from frappe.utils.verified_command import get_signed_params
 
@@ -130,21 +132,18 @@
 		self.party = lead.name
 
 	def auto_assign(self):
-		from frappe.desk.form.assign_to import add as add_assignemnt
-
 		existing_assignee = self.get_assignee_from_latest_opportunity()
 		if existing_assignee:
 			# If the latest opportunity is assigned to someone
 			# Assign the appointment to the same
-			add_assignemnt({"doctype": self.doctype, "name": self.name, "assign_to": [existing_assignee]})
+			self.assign_agent(existing_assignee)
 			return
 		if self._assign:
 			return
 		available_agents = _get_agents_sorted_by_asc_workload(getdate(self.scheduled_time))
 		for agent in available_agents:
 			if _check_agent_availability(agent, self.scheduled_time):
-				agent = agent[0]
-				add_assignemnt({"doctype": self.doctype, "name": self.name, "assign_to": [agent]})
+				self.assign_agent(agent[0])
 			break
 
 	def get_assignee_from_latest_opportunity(self):
@@ -199,9 +198,15 @@
 		params = {"email": self.customer_email, "appointment": self.name}
 		return get_url(verify_route + "?" + get_signed_params(params))
 
+	def assign_agent(self, agent):
+		if not frappe.has_permission(doc=self, user=agent):
+			add_docshare(self.doctype, self.name, agent, flags={"ignore_share_permission": True})
+
+		add_assignment({"doctype": self.doctype, "name": self.name, "assign_to": [agent]})
+
 
 def _get_agents_sorted_by_asc_workload(date):
-	appointments = frappe.db.get_list("Appointment", fields="*")
+	appointments = frappe.get_all("Appointment", fields="*")
 	agent_list = _get_agent_list_as_strings()
 	if not appointments:
 		return agent_list
@@ -226,7 +231,7 @@
 
 
 def _check_agent_availability(agent_email, scheduled_time):
-	appointemnts_at_scheduled_time = frappe.get_list(
+	appointemnts_at_scheduled_time = frappe.get_all(
 		"Appointment", filters={"scheduled_time": scheduled_time}
 	)
 	for appointment in appointemnts_at_scheduled_time:
diff --git a/erpnext/crm/doctype/appointment_booking_settings/appointment_booking_settings.json b/erpnext/crm/doctype/appointment_booking_settings/appointment_booking_settings.json
index 4b26e49..436eb10 100644
--- a/erpnext/crm/doctype/appointment_booking_settings/appointment_booking_settings.json
+++ b/erpnext/crm/doctype/appointment_booking_settings/appointment_booking_settings.json
@@ -1,4 +1,5 @@
 {
+ "actions": [],
  "creation": "2019-08-27 10:56:48.309824",
  "doctype": "DocType",
  "editable_grid": 1,
@@ -101,7 +102,8 @@
   }
  ],
  "issingle": 1,
- "modified": "2019-11-26 12:14:17.669366",
+ "links": [],
+ "modified": "2022-12-15 11:10:13.517742",
  "modified_by": "Administrator",
  "module": "CRM",
  "name": "Appointment Booking Settings",
@@ -118,13 +120,6 @@
    "write": 1
   },
   {
-   "email": 1,
-   "print": 1,
-   "read": 1,
-   "role": "Guest",
-   "share": 1
-  },
-  {
    "create": 1,
    "email": 1,
    "print": 1,
@@ -147,5 +142,6 @@
  "quick_entry": 1,
  "sort_field": "modified",
  "sort_order": "DESC",
+ "states": [],
  "track_changes": 1
 }
\ No newline at end of file
diff --git a/erpnext/hooks.py b/erpnext/hooks.py
index fd19d25..7d72c76 100644
--- a/erpnext/hooks.py
+++ b/erpnext/hooks.py
@@ -420,6 +420,7 @@
 		"erpnext.loan_management.doctype.process_loan_security_shortfall.process_loan_security_shortfall.create_process_loan_security_shortfall",
 		"erpnext.loan_management.doctype.process_loan_interest_accrual.process_loan_interest_accrual.process_loan_interest_accrual_for_term_loans",
 		"erpnext.crm.utils.open_leads_opportunities_based_on_todays_event",
+		"erpnext.stock.doctype.stock_entry.stock_entry.audit_incorrect_valuation_entries",
 	],
 	"monthly_long": [
 		"erpnext.accounts.deferred_revenue.process_deferred_accounting",
diff --git a/erpnext/public/js/controllers/transaction.js b/erpnext/public/js/controllers/transaction.js
index 58d8de2..aa57bc2 100644
--- a/erpnext/public/js/controllers/transaction.js
+++ b/erpnext/public/js/controllers/transaction.js
@@ -298,7 +298,7 @@
 	}
 
 	make_payment_request() {
-		var me = this;
+		let me = this;
 		const payment_request_type = (in_list(['Sales Order', 'Sales Invoice'], this.frm.doc.doctype))
 			? "Inward" : "Outward";
 
@@ -314,7 +314,7 @@
 			},
 			callback: function(r) {
 				if(!r.exc){
-					var doc = frappe.model.sync(r.message);
+					frappe.model.sync(r.message);
 					frappe.set_route("Form", r.message.doctype, r.message.name);
 				}
 			}
diff --git a/erpnext/stock/doctype/pick_list/pick_list.py b/erpnext/stock/doctype/pick_list/pick_list.py
index 5de7fed..aff5e05 100644
--- a/erpnext/stock/doctype/pick_list/pick_list.py
+++ b/erpnext/stock/doctype/pick_list/pick_list.py
@@ -192,13 +192,13 @@
 
 			if item_map.get(key):
 				item_map[key].qty += item.qty
-				item_map[key].stock_qty += item.stock_qty
+				item_map[key].stock_qty += flt(item.stock_qty, item.precision("stock_qty"))
 			else:
 				item_map[key] = item
 
 			# maintain count of each item (useful to limit get query)
 			self.item_count_map.setdefault(item_code, 0)
-			self.item_count_map[item_code] += item.stock_qty
+			self.item_count_map[item_code] += flt(item.stock_qty, item.precision("stock_qty"))
 
 		return item_map.values()
 
diff --git a/erpnext/stock/doctype/serial_no/serial_no.py b/erpnext/stock/doctype/serial_no/serial_no.py
index a2748d0..541d4d1 100644
--- a/erpnext/stock/doctype/serial_no/serial_no.py
+++ b/erpnext/stock/doctype/serial_no/serial_no.py
@@ -766,13 +766,13 @@
 
 @frappe.whitelist()
 def auto_fetch_serial_number(
-	qty: float,
+	qty: int,
 	item_code: str,
 	warehouse: str,
 	posting_date: Optional[str] = None,
 	batch_nos: Optional[Union[str, List[str]]] = None,
 	for_doctype: Optional[str] = None,
-	exclude_sr_nos: Optional[List[str]] = None,
+	exclude_sr_nos=None,
 ) -> List[str]:
 
 	filters = frappe._dict({"item_code": item_code, "warehouse": warehouse})
diff --git a/erpnext/stock/doctype/stock_entry/stock_entry.py b/erpnext/stock/doctype/stock_entry/stock_entry.py
index d401f81..a047a9b 100644
--- a/erpnext/stock/doctype/stock_entry/stock_entry.py
+++ b/erpnext/stock/doctype/stock_entry/stock_entry.py
@@ -4,12 +4,24 @@
 
 import json
 from collections import defaultdict
+from typing import Dict
 
 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
+from frappe.utils import (
+	add_days,
+	cint,
+	comma_or,
+	cstr,
+	flt,
+	format_time,
+	formatdate,
+	getdate,
+	nowdate,
+	today,
+)
 
 import erpnext
 from erpnext.accounts.general_ledger import process_gl_map
@@ -2700,3 +2712,62 @@
 		)
 		.orderby(stock_entry.creation, stock_entry_detail.item_code, stock_entry_detail.idx)
 	).run(as_dict=1)
+
+
+def audit_incorrect_valuation_entries():
+	# Audit of stock transfer entries having incorrect valuation
+	from erpnext.controllers.stock_controller import create_repost_item_valuation_entry
+
+	stock_entries = get_incorrect_stock_entries()
+
+	for stock_entry, values in stock_entries.items():
+		reposting_data = frappe._dict(
+			{
+				"posting_date": values.posting_date,
+				"posting_time": values.posting_time,
+				"voucher_type": "Stock Entry",
+				"voucher_no": stock_entry,
+				"company": values.company,
+			}
+		)
+
+		create_repost_item_valuation_entry(reposting_data)
+
+
+def get_incorrect_stock_entries() -> Dict:
+	stock_entry = frappe.qb.DocType("Stock Entry")
+	stock_ledger_entry = frappe.qb.DocType("Stock Ledger Entry")
+	transfer_purposes = [
+		"Material Transfer",
+		"Material Transfer for Manufacture",
+		"Send to Subcontractor",
+	]
+
+	query = (
+		frappe.qb.from_(stock_entry)
+		.inner_join(stock_ledger_entry)
+		.on(stock_entry.name == stock_ledger_entry.voucher_no)
+		.select(
+			stock_entry.name,
+			stock_entry.company,
+			stock_entry.posting_date,
+			stock_entry.posting_time,
+			Sum(stock_ledger_entry.stock_value_difference).as_("stock_value"),
+		)
+		.where(
+			(stock_entry.docstatus == 1)
+			& (stock_entry.purpose.isin(transfer_purposes))
+			& (stock_ledger_entry.modified > add_days(today(), -2))
+		)
+		.groupby(stock_ledger_entry.voucher_detail_no)
+		.having(Sum(stock_ledger_entry.stock_value_difference) != 0)
+	)
+
+	data = query.run(as_dict=True)
+	stock_entries = {}
+
+	for row in data:
+		if abs(row.stock_value) > 0.1 and row.name not in stock_entries:
+			stock_entries.setdefault(row.name, row)
+
+	return stock_entries
diff --git a/erpnext/stock/doctype/stock_entry/test_stock_entry.py b/erpnext/stock/doctype/stock_entry/test_stock_entry.py
index b574b71..680d209 100644
--- a/erpnext/stock/doctype/stock_entry/test_stock_entry.py
+++ b/erpnext/stock/doctype/stock_entry/test_stock_entry.py
@@ -5,7 +5,7 @@
 import frappe
 from frappe.permissions import add_user_permission, remove_user_permission
 from frappe.tests.utils import FrappeTestCase, change_settings
-from frappe.utils import add_days, flt, nowdate, nowtime, today
+from frappe.utils import add_days, flt, now, nowdate, nowtime, today
 
 from erpnext.accounts.doctype.account.test_account import get_inventory_account
 from erpnext.stock.doctype.item.test_item import (
@@ -17,6 +17,8 @@
 from erpnext.stock.doctype.serial_no.serial_no import *  # noqa
 from erpnext.stock.doctype.stock_entry.stock_entry import (
 	FinishedGoodError,
+	audit_incorrect_valuation_entries,
+	get_incorrect_stock_entries,
 	move_sample_to_retention_warehouse,
 )
 from erpnext.stock.doctype.stock_entry.stock_entry_utils import make_stock_entry
@@ -1614,6 +1616,44 @@
 
 		self.assertRaises(BatchExpiredError, se.save)
 
+	def test_audit_incorrect_stock_entries(self):
+		item_code = "Test Incorrect Valuation Rate Item - 001"
+		create_item(item_code=item_code, is_stock_item=1)
+
+		make_stock_entry(
+			item_code=item_code,
+			purpose="Material Receipt",
+			posting_date=add_days(nowdate(), -10),
+			qty=2,
+			rate=500,
+			to_warehouse="_Test Warehouse - _TC",
+		)
+
+		transfer_entry = make_stock_entry(
+			item_code=item_code,
+			purpose="Material Transfer",
+			qty=2,
+			rate=500,
+			from_warehouse="_Test Warehouse - _TC",
+			to_warehouse="_Test Warehouse 1 - _TC",
+		)
+
+		sle_name = frappe.db.get_value(
+			"Stock Ledger Entry", {"voucher_no": transfer_entry.name, "actual_qty": (">", 0)}, "name"
+		)
+
+		frappe.db.set_value(
+			"Stock Ledger Entry", sle_name, {"modified": add_days(now(), -1), "stock_value_difference": 10}
+		)
+
+		stock_entries = get_incorrect_stock_entries()
+		self.assertTrue(transfer_entry.name in stock_entries)
+
+		audit_incorrect_valuation_entries()
+
+		stock_entries = get_incorrect_stock_entries()
+		self.assertFalse(transfer_entry.name in stock_entries)
+
 
 def make_serialized_item(**args):
 	args = frappe._dict(args)
diff --git a/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.py b/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.py
index 3a0b38a..398b3c9 100644
--- a/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.py
+++ b/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.py
@@ -715,8 +715,8 @@
 def get_stock_balance_for(
 	item_code: str,
 	warehouse: str,
-	posting_date: str,
-	posting_time: str,
+	posting_date,
+	posting_time,
 	batch_no: Optional[str] = None,
 	with_valuation_rate: bool = True,
 ):
diff --git a/erpnext/www/book-appointment/__init__.py b/erpnext/www/book-appointment/__init__.py
deleted file mode 100644
index e69de29..0000000
--- a/erpnext/www/book-appointment/__init__.py
+++ /dev/null
diff --git a/erpnext/www/book-appointment/verify/__init__.py b/erpnext/www/book-appointment/verify/__init__.py
deleted file mode 100644
index e69de29..0000000
--- a/erpnext/www/book-appointment/verify/__init__.py
+++ /dev/null
diff --git a/erpnext/www/book_appointment/index.js b/erpnext/www/book_appointment/index.js
index 46ac155..d02cdad 100644
--- a/erpnext/www/book_appointment/index.js
+++ b/erpnext/www/book_appointment/index.js
@@ -2,8 +2,6 @@
     initialise_select_date();
 })
 
-window.holiday_list = [];
-
 async function initialise_select_date() {
     navigate_to_page(1);
     await get_global_variables();
@@ -20,7 +18,6 @@
     window.timezones = (await frappe.call({
         method:'erpnext.www.book_appointment.index.get_timezones'
     })).message;
-    window.holiday_list = window.appointment_settings.holiday_list;
 }
 
 function setup_timezone_selector() {
diff --git a/erpnext/www/book_appointment/index.py b/erpnext/www/book_appointment/index.py
index 06e99da..dfca946 100644
--- a/erpnext/www/book_appointment/index.py
+++ b/erpnext/www/book_appointment/index.py
@@ -26,8 +26,12 @@
 
 @frappe.whitelist(allow_guest=True)
 def get_appointment_settings():
-	settings = frappe.get_doc("Appointment Booking Settings")
-	settings.holiday_list = frappe.get_doc("Holiday List", settings.holiday_list)
+	settings = frappe.get_cached_value(
+		"Appointment Booking Settings",
+		None,
+		["advance_booking_days", "appointment_duration", "success_redirect_url"],
+		as_dict=True,
+	)
 	return settings
 
 
@@ -106,7 +110,7 @@
 	appointment.customer_details = contact.get("notes", None)
 	appointment.customer_email = contact.get("email", None)
 	appointment.status = "Open"
-	appointment.insert()
+	appointment.insert(ignore_permissions=True)
 	return appointment
 
 
diff --git a/erpnext/www/book_appointment/verify/index.py b/erpnext/www/book_appointment/verify/index.py
index 1a5ba9d..3beb866 100644
--- a/erpnext/www/book_appointment/verify/index.py
+++ b/erpnext/www/book_appointment/verify/index.py
@@ -2,7 +2,6 @@
 from frappe.utils.verified_command import verify_request
 
 
-@frappe.whitelist(allow_guest=True)
 def get_context(context):
 	if not verify_request():
 		context.success = False