Merge pull request #34189 from rohitwaghchaure/prevent-to-make-item-price-for-template

fix: user shouldn't able to make item price for item template
diff --git a/CODEOWNERS b/CODEOWNERS
index e406f8f..c4ea163 100644
--- a/CODEOWNERS
+++ b/CODEOWNERS
@@ -4,7 +4,7 @@
 # the repo. Unless a later match takes precedence,
 
 erpnext/accounts/               @nextchamp-saqib @deepeshgarg007 @ruthra-kumar
-erpnext/assets/                 @nextchamp-saqib @deepeshgarg007 @ruthra-kumar
+erpnext/assets/                 @anandbaburajan @deepeshgarg007
 erpnext/loan_management/        @nextchamp-saqib @deepeshgarg007
 erpnext/regional                @nextchamp-saqib @deepeshgarg007 @ruthra-kumar
 erpnext/selling                 @nextchamp-saqib @deepeshgarg007 @ruthra-kumar
@@ -16,6 +16,7 @@
 erpnext/manufacturing/          @rohitwaghchaure @s-aga-r
 erpnext/quality_management/     @rohitwaghchaure @s-aga-r
 erpnext/stock/                  @rohitwaghchaure @s-aga-r
+erpnext/subcontracting          @rohitwaghchaure @s-aga-r
 
 erpnext/crm/                    @NagariaHussain
 erpnext/education/              @rutwikhdev
diff --git a/README.md b/README.md
index 0708266..44bd729 100644
--- a/README.md
+++ b/README.md
@@ -65,7 +65,7 @@
 1. [Frappe School](https://frappe.school) - Learn Frappe Framework and ERPNext from the various courses by the maintainers or from the community.
 2. [Official documentation](https://docs.erpnext.com/) - Extensive documentation for ERPNext.
 3. [Discussion Forum](https://discuss.erpnext.com/) - Engage with community of ERPNext users and service providers.
-4. [Telegram Group](https://t.me/erpnexthelp) - Get instant help from huge community of users.
+4. [Telegram Group](https://erpnext_public.t.me) - Get instant help from huge community of users.
 
 
 ## Contributing
diff --git a/erpnext/accounts/doctype/bank/bank.js b/erpnext/accounts/doctype/bank/bank.js
index 059e1d3..35d606b 100644
--- a/erpnext/accounts/doctype/bank/bank.js
+++ b/erpnext/accounts/doctype/bank/bank.js
@@ -118,6 +118,10 @@
 	}
 
 	plaid_success(token, response) {
-		frappe.show_alert({ message: __('Plaid Link Updated'), indicator: 'green' });
+		frappe.xcall('erpnext.erpnext_integrations.doctype.plaid_settings.plaid_settings.update_bank_account_ids', {
+			response: response,
+		}).then(() => {
+			frappe.show_alert({ message: __('Plaid Link Updated'), indicator: 'green' });
+		});
 	}
 };
diff --git a/erpnext/accounts/doctype/bank_reconciliation_tool/bank_reconciliation_tool.js b/erpnext/accounts/doctype/bank_reconciliation_tool/bank_reconciliation_tool.js
index c083189..ae84154 100644
--- a/erpnext/accounts/doctype/bank_reconciliation_tool/bank_reconciliation_tool.js
+++ b/erpnext/accounts/doctype/bank_reconciliation_tool/bank_reconciliation_tool.js
@@ -155,7 +155,7 @@
 		}
 	},
 
-	render_chart: frappe.utils.debounce((frm) => {
+	render_chart(frm) {
 		frm.cards_manager = new erpnext.accounts.bank_reconciliation.NumberCardManager(
 			{
 				$reconciliation_tool_cards: frm.get_field(
@@ -167,7 +167,7 @@
 				currency: frm.currency,
 			}
 		);
-	}, 500),
+	},
 
 	render(frm) {
 		if (frm.doc.bank_account) {
diff --git a/erpnext/accounts/doctype/bank_reconciliation_tool/bank_reconciliation_tool.py b/erpnext/accounts/doctype/bank_reconciliation_tool/bank_reconciliation_tool.py
index 4ba6146..c4a23a6 100644
--- a/erpnext/accounts/doctype/bank_reconciliation_tool/bank_reconciliation_tool.py
+++ b/erpnext/accounts/doctype/bank_reconciliation_tool/bank_reconciliation_tool.py
@@ -10,7 +10,7 @@
 from frappe.query_builder.custom import ConstantColumn
 from frappe.utils import cint, flt
 
-from erpnext.accounts.doctype.bank_transaction.bank_transaction import get_paid_amount
+from erpnext.accounts.doctype.bank_transaction.bank_transaction import get_total_allocated_amount
 from erpnext.accounts.report.bank_reconciliation_statement.bank_reconciliation_statement import (
 	get_amounts_not_reflected_in_system,
 	get_entries,
@@ -28,7 +28,7 @@
 	filters = []
 	filters.append(["bank_account", "=", bank_account])
 	filters.append(["docstatus", "=", 1])
-	filters.append(["unallocated_amount", ">", 0])
+	filters.append(["unallocated_amount", ">", 0.0])
 	if to_date:
 		filters.append(["date", "<=", to_date])
 	if from_date:
@@ -58,7 +58,7 @@
 @frappe.whitelist()
 def get_account_balance(bank_account, till_date):
 	# returns account balance till the specified date
-	account = frappe.get_cached_value("Bank Account", bank_account, "account")
+	account = frappe.db.get_value("Bank Account", bank_account, "account")
 	filters = frappe._dict(
 		{"account": account, "report_date": till_date, "include_pos_transactions": 1}
 	)
@@ -66,7 +66,7 @@
 
 	balance_as_per_system = get_balance_on(filters["account"], filters["report_date"])
 
-	total_debit, total_credit = 0, 0
+	total_debit, total_credit = 0.0, 0.0
 	for d in data:
 		total_debit += flt(d.debit)
 		total_credit += flt(d.credit)
@@ -131,10 +131,8 @@
 		fieldname=["name", "deposit", "withdrawal", "bank_account"],
 		as_dict=True,
 	)[0]
-	company_account = frappe.get_cached_value(
-		"Bank Account", bank_transaction.bank_account, "account"
-	)
-	account_type = frappe.get_cached_value("Account", second_account, "account_type")
+	company_account = frappe.get_value("Bank Account", bank_transaction.bank_account, "account")
+	account_type = frappe.db.get_value("Account", second_account, "account_type")
 	if account_type in ["Receivable", "Payable"]:
 		if not (party_type and party):
 			frappe.throw(
@@ -147,10 +145,8 @@
 	accounts.append(
 		{
 			"account": second_account,
-			"credit_in_account_currency": bank_transaction.deposit if bank_transaction.deposit > 0 else 0,
-			"debit_in_account_currency": bank_transaction.withdrawal
-			if bank_transaction.withdrawal > 0
-			else 0,
+			"credit_in_account_currency": bank_transaction.deposit,
+			"debit_in_account_currency": bank_transaction.withdrawal,
 			"party_type": party_type,
 			"party": party,
 		}
@@ -160,14 +156,12 @@
 		{
 			"account": company_account,
 			"bank_account": bank_transaction.bank_account,
-			"credit_in_account_currency": bank_transaction.withdrawal
-			if bank_transaction.withdrawal > 0
-			else 0,
-			"debit_in_account_currency": bank_transaction.deposit if bank_transaction.deposit > 0 else 0,
+			"credit_in_account_currency": bank_transaction.withdrawal,
+			"debit_in_account_currency": bank_transaction.deposit,
 		}
 	)
 
-	company = frappe.get_cached_value("Account", company_account, "company")
+	company = frappe.get_value("Account", company_account, "company")
 
 	journal_entry_dict = {
 		"voucher_type": entry_type,
@@ -187,16 +181,22 @@
 	journal_entry.insert()
 	journal_entry.submit()
 
-	if bank_transaction.deposit > 0:
+	if bank_transaction.deposit > 0.0:
 		paid_amount = bank_transaction.deposit
 	else:
 		paid_amount = bank_transaction.withdrawal
 
 	vouchers = json.dumps(
-		[{"payment_doctype": "Journal Entry", "payment_name": journal_entry.name, "amount": paid_amount}]
+		[
+			{
+				"payment_doctype": "Journal Entry",
+				"payment_name": journal_entry.name,
+				"amount": paid_amount,
+			}
+		]
 	)
 
-	return reconcile_vouchers(bank_transaction.name, vouchers)
+	return reconcile_vouchers(bank_transaction_name, vouchers)
 
 
 @frappe.whitelist()
@@ -220,12 +220,10 @@
 		as_dict=True,
 	)[0]
 	paid_amount = bank_transaction.unallocated_amount
-	payment_type = "Receive" if bank_transaction.deposit > 0 else "Pay"
+	payment_type = "Receive" if bank_transaction.deposit > 0.0 else "Pay"
 
-	company_account = frappe.get_cached_value(
-		"Bank Account", bank_transaction.bank_account, "account"
-	)
-	company = frappe.get_cached_value("Account", company_account, "company")
+	company_account = frappe.get_value("Bank Account", bank_transaction.bank_account, "account")
+	company = frappe.get_value("Account", company_account, "company")
 	payment_entry_dict = {
 		"company": company,
 		"payment_type": payment_type,
@@ -261,9 +259,15 @@
 
 	payment_entry.submit()
 	vouchers = json.dumps(
-		[{"payment_doctype": "Payment Entry", "payment_name": payment_entry.name, "amount": paid_amount}]
+		[
+			{
+				"payment_doctype": "Payment Entry",
+				"payment_name": payment_entry.name,
+				"amount": paid_amount,
+			}
+		]
 	)
-	return reconcile_vouchers(bank_transaction.name, vouchers)
+	return reconcile_vouchers(bank_transaction_name, vouchers)
 
 
 @frappe.whitelist()
@@ -345,59 +349,7 @@
 	# updated clear date of all the vouchers based on the bank transaction
 	vouchers = json.loads(vouchers)
 	transaction = frappe.get_doc("Bank Transaction", bank_transaction_name)
-	company_account = frappe.get_cached_value("Bank Account", transaction.bank_account, "account")
-
-	if transaction.unallocated_amount == 0:
-		frappe.throw(_("This bank transaction is already fully reconciled"))
-	total_amount = 0
-	for voucher in vouchers:
-		voucher["payment_entry"] = frappe.get_doc(voucher["payment_doctype"], voucher["payment_name"])
-		total_amount += get_paid_amount(
-			frappe._dict(
-				{
-					"payment_document": voucher["payment_doctype"],
-					"payment_entry": voucher["payment_name"],
-				}
-			),
-			transaction.currency,
-			company_account,
-		)
-
-	if total_amount > transaction.unallocated_amount:
-		frappe.throw(
-			_(
-				"The sum total of amounts of all selected vouchers should be less than the unallocated amount of the bank transaction"
-			)
-		)
-	account = frappe.get_cached_value("Bank Account", transaction.bank_account, "account")
-
-	for voucher in vouchers:
-		gl_entry = frappe.db.get_value(
-			"GL Entry",
-			dict(
-				account=account, voucher_type=voucher["payment_doctype"], voucher_no=voucher["payment_name"]
-			),
-			["credit_in_account_currency as credit", "debit_in_account_currency as debit"],
-			as_dict=1,
-		)
-		gl_amount, transaction_amount = (
-			(gl_entry.credit, transaction.deposit)
-			if gl_entry.credit > 0
-			else (gl_entry.debit, transaction.withdrawal)
-		)
-		allocated_amount = gl_amount if gl_amount >= transaction_amount else transaction_amount
-
-		transaction.append(
-			"payment_entries",
-			{
-				"payment_document": voucher["payment_entry"].doctype,
-				"payment_entry": voucher["payment_entry"].name,
-				"allocated_amount": allocated_amount,
-			},
-		)
-
-	transaction.save()
-	transaction.update_allocations()
+	transaction.add_payment_entries(vouchers)
 	return frappe.get_doc("Bank Transaction", bank_transaction_name)
 
 
@@ -416,9 +368,9 @@
 	bank_account = frappe.db.get_values(
 		"Bank Account", transaction.bank_account, ["account", "company"], as_dict=True
 	)[0]
-	(account, company) = (bank_account.account, bank_account.company)
+	(gl_account, company) = (bank_account.account, bank_account.company)
 	matching = check_matching(
-		account,
+		gl_account,
 		company,
 		transaction,
 		document_types,
@@ -428,7 +380,27 @@
 		from_reference_date,
 		to_reference_date,
 	)
-	return matching
+	return subtract_allocations(gl_account, matching)
+
+
+def subtract_allocations(gl_account, vouchers):
+	"Look up & subtract any existing Bank Transaction allocations"
+	copied = []
+	for voucher in vouchers:
+		rows = get_total_allocated_amount(voucher[1], voucher[2])
+		amount = None
+		for row in rows:
+			if row["gl_account"] == gl_account:
+				amount = row["total"]
+				break
+
+		if amount:
+			l = list(voucher)
+			l[3] -= amount
+			copied.append(tuple(l))
+		else:
+			copied.append(voucher)
+	return copied
 
 
 def check_matching(
@@ -442,6 +414,7 @@
 	from_reference_date,
 	to_reference_date,
 ):
+	exact_match = True if "exact_match" in document_types else False
 	# combine all types of vouchers
 	subquery = get_queries(
 		bank_account,
@@ -453,10 +426,11 @@
 		filter_by_reference_date,
 		from_reference_date,
 		to_reference_date,
+		exact_match,
 	)
 	filters = {
 		"amount": transaction.unallocated_amount,
-		"payment_type": "Receive" if transaction.deposit > 0 else "Pay",
+		"payment_type": "Receive" if transaction.deposit > 0.0 else "Pay",
 		"reference_no": transaction.reference_number,
 		"party_type": transaction.party_type,
 		"party": transaction.party,
@@ -465,7 +439,9 @@
 
 	matching_vouchers = []
 
-	matching_vouchers.extend(get_loan_vouchers(bank_account, transaction, document_types, filters))
+	matching_vouchers.extend(
+		get_loan_vouchers(bank_account, transaction, document_types, filters, exact_match)
+	)
 
 	for query in subquery:
 		matching_vouchers.extend(
@@ -487,10 +463,10 @@
 	filter_by_reference_date,
 	from_reference_date,
 	to_reference_date,
+	exact_match,
 ):
 	# get queries to get matching vouchers
-	amount_condition = "=" if "exact_match" in document_types else "<="
-	account_from_to = "paid_to" if transaction.deposit > 0 else "paid_from"
+	account_from_to = "paid_to" if transaction.deposit > 0.0 else "paid_from"
 	queries = []
 
 	# get matching queries from all the apps
@@ -501,7 +477,7 @@
 				company,
 				transaction,
 				document_types,
-				amount_condition,
+				exact_match,
 				account_from_to,
 				from_date,
 				to_date,
@@ -520,7 +496,7 @@
 	company,
 	transaction,
 	document_types,
-	amount_condition,
+	exact_match,
 	account_from_to,
 	from_date,
 	to_date,
@@ -530,8 +506,8 @@
 ):
 	queries = []
 	if "payment_entry" in document_types:
-		pe_amount_matching = get_pe_matching_query(
-			amount_condition,
+		query = get_pe_matching_query(
+			exact_match,
 			account_from_to,
 			transaction,
 			from_date,
@@ -540,11 +516,11 @@
 			from_reference_date,
 			to_reference_date,
 		)
-		queries.extend([pe_amount_matching])
+		queries.append(query)
 
 	if "journal_entry" in document_types:
-		je_amount_matching = get_je_matching_query(
-			amount_condition,
+		query = get_je_matching_query(
+			exact_match,
 			transaction,
 			from_date,
 			to_date,
@@ -552,34 +528,70 @@
 			from_reference_date,
 			to_reference_date,
 		)
-		queries.extend([je_amount_matching])
+		queries.append(query)
 
-	if transaction.deposit > 0 and "sales_invoice" in document_types:
-		si_amount_matching = get_si_matching_query(amount_condition)
-		queries.extend([si_amount_matching])
+	if transaction.deposit > 0.0 and "sales_invoice" in document_types:
+		query = get_si_matching_query(exact_match)
+		queries.append(query)
 
-	if transaction.withdrawal > 0:
+	if transaction.withdrawal > 0.0:
 		if "purchase_invoice" in document_types:
-			pi_amount_matching = get_pi_matching_query(amount_condition)
-			queries.extend([pi_amount_matching])
+			query = get_pi_matching_query(exact_match)
+			queries.append(query)
+
+	if "bank_transaction" in document_types:
+		query = get_bt_matching_query(exact_match, transaction)
+		queries.append(query)
 
 	return queries
 
 
-def get_loan_vouchers(bank_account, transaction, document_types, filters):
+def get_loan_vouchers(bank_account, transaction, document_types, filters, exact_match):
 	vouchers = []
-	amount_condition = True if "exact_match" in document_types else False
 
-	if transaction.withdrawal > 0 and "loan_disbursement" in document_types:
-		vouchers.extend(get_ld_matching_query(bank_account, amount_condition, filters))
+	if transaction.withdrawal > 0.0 and "loan_disbursement" in document_types:
+		vouchers.extend(get_ld_matching_query(bank_account, exact_match, filters))
 
-	if transaction.deposit > 0 and "loan_repayment" in document_types:
-		vouchers.extend(get_lr_matching_query(bank_account, amount_condition, filters))
+	if transaction.deposit > 0.0 and "loan_repayment" in document_types:
+		vouchers.extend(get_lr_matching_query(bank_account, exact_match, filters))
 
 	return vouchers
 
 
-def get_ld_matching_query(bank_account, amount_condition, filters):
+def get_bt_matching_query(exact_match, transaction):
+	# get matching bank transaction query
+	# find bank transactions in the same bank account with opposite sign
+	# same bank account must have same company and currency
+	field = "deposit" if transaction.withdrawal > 0.0 else "withdrawal"
+
+	return f"""
+
+		SELECT
+			(CASE WHEN reference_number = %(reference_no)s THEN 1 ELSE 0 END
+			+ CASE WHEN {field} = %(amount)s THEN 1 ELSE 0 END
+			+ CASE WHEN ( party_type = %(party_type)s AND party = %(party)s ) THEN 1 ELSE 0 END
+			+ CASE WHEN unallocated_amount = %(amount)s THEN 1 ELSE 0 END
+			+ 1) AS rank,
+			'Bank Transaction' AS doctype,
+			name,
+			unallocated_amount AS paid_amount,
+			reference_number AS reference_no,
+			date AS reference_date,
+			party,
+			party_type,
+			date AS posting_date,
+			currency
+		FROM
+			`tabBank Transaction`
+		WHERE
+			status != 'Reconciled'
+			AND name != '{transaction.name}'
+			AND bank_account = '{transaction.bank_account}'
+			AND {field} {'= %(amount)s' if exact_match else '> 0.0'}
+	"""
+
+
+def get_ld_matching_query(bank_account, exact_match, filters):
 	loan_disbursement = frappe.qb.DocType("Loan Disbursement")
 	matching_reference = loan_disbursement.reference_number == filters.get("reference_number")
 	matching_party = loan_disbursement.applicant_type == filters.get(
@@ -607,17 +619,17 @@
 		.where(loan_disbursement.disbursement_account == bank_account)
 	)
 
-	if amount_condition:
+	if exact_match:
 		query.where(loan_disbursement.disbursed_amount == filters.get("amount"))
 	else:
-		query.where(loan_disbursement.disbursed_amount <= filters.get("amount"))
+		query.where(loan_disbursement.disbursed_amount > 0.0)
 
 	vouchers = query.run(as_list=True)
 
 	return vouchers
 
 
-def get_lr_matching_query(bank_account, amount_condition, filters):
+def get_lr_matching_query(bank_account, exact_match, filters):
 	loan_repayment = frappe.qb.DocType("Loan Repayment")
 	matching_reference = loan_repayment.reference_number == filters.get("reference_number")
 	matching_party = loan_repayment.applicant_type == filters.get(
@@ -648,10 +660,10 @@
 	if frappe.db.has_column("Loan Repayment", "repay_from_salary"):
 		query = query.where((loan_repayment.repay_from_salary == 0))
 
-	if amount_condition:
+	if exact_match:
 		query.where(loan_repayment.amount_paid == filters.get("amount"))
 	else:
-		query.where(loan_repayment.amount_paid <= filters.get("amount"))
+		query.where(loan_repayment.amount_paid > 0.0)
 
 	vouchers = query.run()
 
@@ -659,7 +671,7 @@
 
 
 def get_pe_matching_query(
-	amount_condition,
+	exact_match,
 	account_from_to,
 	transaction,
 	from_date,
@@ -669,7 +681,7 @@
 	to_reference_date,
 ):
 	# get matching payment entries query
-	if transaction.deposit > 0:
+	if transaction.deposit > 0.0:
 		currency_field = "paid_to_account_currency as currency"
 	else:
 		currency_field = "paid_from_account_currency as currency"
@@ -684,7 +696,8 @@
 	return f"""
 		SELECT
 			(CASE WHEN reference_no=%(reference_no)s THEN 1 ELSE 0 END
-			+ CASE WHEN (party_type = %(party_type)s AND party = %(party)s ) THEN 1 ELSE 0  END
+			+ CASE WHEN (party_type = %(party_type)s AND party = %(party)s ) THEN 1 ELSE 0 END
+			+ CASE WHEN paid_amount = %(amount)s THEN 1 ELSE 0 END
 			+ 1 ) AS rank,
 			'Payment Entry' as doctype,
 			name,
@@ -698,20 +711,19 @@
 		FROM
 			`tabPayment Entry`
 		WHERE
-			paid_amount {amount_condition} %(amount)s
-			AND docstatus = 1
+			docstatus = 1
 			AND payment_type IN (%(payment_type)s, 'Internal Transfer')
 			AND ifnull(clearance_date, '') = ""
 			AND {account_from_to} = %(bank_account)s
+			AND paid_amount {'= %(amount)s' if exact_match else '> 0.0'}
 			{filter_by_date}
 			{filter_by_reference_no}
 		order by{order_by}
-
 	"""
 
 
 def get_je_matching_query(
-	amount_condition,
+	exact_match,
 	transaction,
 	from_date,
 	to_date,
@@ -723,7 +735,7 @@
 	# We have mapping at the bank level
 	# So one bank could have both types of bank accounts like asset and liability
 	# So cr_or_dr should be judged only on basis of withdrawal and deposit and not account type
-	cr_or_dr = "credit" if transaction.withdrawal > 0 else "debit"
+	cr_or_dr = "credit" if transaction.withdrawal > 0.0 else "debit"
 	filter_by_date = f"AND je.posting_date between '{from_date}' and '{to_date}'"
 	order_by = " je.posting_date"
 	filter_by_reference_no = ""
@@ -735,26 +747,29 @@
 	return f"""
 		SELECT
 			(CASE WHEN je.cheque_no=%(reference_no)s THEN 1 ELSE 0 END
+			+ CASE WHEN jea.{cr_or_dr}_in_account_currency = %(amount)s THEN 1 ELSE 0 END
 			+ 1) AS rank ,
-			'Journal Entry' as doctype,
+			'Journal Entry' AS doctype,
 			je.name,
-			jea.{cr_or_dr}_in_account_currency as paid_amount,
-			je.cheque_no as reference_no,
-			je.cheque_date as reference_date,
-			je.pay_to_recd_from as party,
+			jea.{cr_or_dr}_in_account_currency AS paid_amount,
+			je.cheque_no AS reference_no,
+			je.cheque_date AS reference_date,
+			je.pay_to_recd_from AS party,
 			jea.party_type,
 			je.posting_date,
-			jea.account_currency as currency
+			jea.account_currency AS currency
 		FROM
-			`tabJournal Entry Account` as jea
+			`tabJournal Entry Account` AS jea
 		JOIN
-			`tabJournal Entry` as je
+			`tabJournal Entry` AS je
 		ON
 			jea.parent = je.name
 		WHERE
-			(je.clearance_date is null or je.clearance_date='0000-00-00')
+			je.docstatus = 1
+			AND je.voucher_type NOT IN ('Opening Entry')
+			AND (je.clearance_date IS NULL OR je.clearance_date='0000-00-00')
 			AND jea.account = %(bank_account)s
-			AND jea.{cr_or_dr}_in_account_currency {amount_condition} %(amount)s
+			AND jea.{cr_or_dr}_in_account_currency {'= %(amount)s' if exact_match else '> 0.0'}
 			AND je.docstatus = 1
 			{filter_by_date}
 			{filter_by_reference_no}
@@ -762,11 +777,12 @@
 	"""
 
 
-def get_si_matching_query(amount_condition):
-	# get matchin sales invoice query
+def get_si_matching_query(exact_match):
+	# get matching sales invoice query
 	return f"""
 		SELECT
-			( CASE WHEN si.customer = %(party)s  THEN 1 ELSE 0  END
+			( CASE WHEN si.customer = %(party)s  THEN 1 ELSE 0 END
+			+ CASE WHEN sip.amount = %(amount)s THEN 1 ELSE 0 END
 			+ 1 ) AS rank,
 			'Sales Invoice' as doctype,
 			si.name,
@@ -784,18 +800,20 @@
 			`tabSales Invoice` as si
 		ON
 			sip.parent = si.name
-		WHERE (sip.clearance_date is null or sip.clearance_date='0000-00-00')
+		WHERE
+			si.docstatus = 1
+			AND (sip.clearance_date is null or sip.clearance_date='0000-00-00')
 			AND sip.account = %(bank_account)s
-			AND sip.amount {amount_condition} %(amount)s
-			AND si.docstatus = 1
+			AND sip.amount {'= %(amount)s' if exact_match else '> 0.0'}
 	"""
 
 
-def get_pi_matching_query(amount_condition):
-	# get matching purchase invoice query
+def get_pi_matching_query(exact_match):
+	# get matching purchase invoice query when they are also used as payment entries (is_paid)
 	return f"""
 		SELECT
 			( CASE WHEN supplier = %(party)s THEN 1 ELSE 0 END
+			+ CASE WHEN paid_amount = %(amount)s THEN 1 ELSE 0 END
 			+ 1 ) AS rank,
 			'Purchase Invoice' as doctype,
 			name,
@@ -809,9 +827,9 @@
 		FROM
 			`tabPurchase Invoice`
 		WHERE
-			paid_amount {amount_condition} %(amount)s
-			AND docstatus = 1
+			docstatus = 1
 			AND is_paid = 1
 			AND ifnull(clearance_date, '') = ""
-			AND cash_bank_account  = %(bank_account)s
+			AND cash_bank_account = %(bank_account)s
+			AND paid_amount {'= %(amount)s' if exact_match else '> 0.0'}
 	"""
diff --git a/erpnext/accounts/doctype/bank_transaction/bank_transaction.js b/erpnext/accounts/doctype/bank_transaction/bank_transaction.js
index 6f2900a..e548b4c 100644
--- a/erpnext/accounts/doctype/bank_transaction/bank_transaction.js
+++ b/erpnext/accounts/doctype/bank_transaction/bank_transaction.js
@@ -12,8 +12,13 @@
 			};
 		});
 	},
-
-	bank_account: function(frm) {
+	refresh(frm) {
+		frm.add_custom_button(__('Unreconcile Transaction'), () => {
+			frm.call('remove_payment_entries')
+			.then( () => frm.refresh() );
+		});
+	},
+	bank_account: function (frm) {
 		set_bank_statement_filter(frm);
 	},
 
@@ -34,6 +39,7 @@
 			"Journal Entry",
 			"Sales Invoice",
 			"Purchase Invoice",
+			"Bank Transaction",
 		];
 	}
 });
@@ -49,7 +55,7 @@
 		frappe
 			.xcall(
 				"erpnext.accounts.doctype.bank_transaction.bank_transaction.unclear_reference_payment",
-				{ doctype: cdt, docname: cdn }
+				{ doctype: cdt, docname: cdn, bt_name: frm.doc.name }
 			)
 			.then((e) => {
 				if (e == "success") {
diff --git a/erpnext/accounts/doctype/bank_transaction/bank_transaction.json b/erpnext/accounts/doctype/bank_transaction/bank_transaction.json
index 2bdaa10..768d2f0 100644
--- a/erpnext/accounts/doctype/bank_transaction/bank_transaction.json
+++ b/erpnext/accounts/doctype/bank_transaction/bank_transaction.json
@@ -20,9 +20,11 @@
   "currency",
   "section_break_10",
   "description",
-  "section_break_14",
   "reference_number",
+  "column_break_10",
   "transaction_id",
+  "transaction_type",
+  "section_break_14",
   "payment_entries",
   "section_break_18",
   "allocated_amount",
@@ -190,11 +192,21 @@
    "label": "Withdrawal",
    "oldfieldname": "credit",
    "options": "currency"
+  },
+  {
+   "fieldname": "column_break_10",
+   "fieldtype": "Column Break"
+  },
+  {
+   "fieldname": "transaction_type",
+   "fieldtype": "Data",
+   "label": "Transaction Type",
+   "length": 50
   }
  ],
  "is_submittable": 1,
  "links": [],
- "modified": "2022-03-21 19:05:04.208222",
+ "modified": "2022-05-29 18:36:50.475964",
  "modified_by": "Administrator",
  "module": "Accounts",
  "name": "Bank Transaction",
@@ -248,4 +260,4 @@
  "states": [],
  "title_field": "bank_account",
  "track_changes": 1
-}
\ No newline at end of file
+}
diff --git a/erpnext/accounts/doctype/bank_transaction/bank_transaction.py b/erpnext/accounts/doctype/bank_transaction/bank_transaction.py
index 9b36c93..1516237 100644
--- a/erpnext/accounts/doctype/bank_transaction/bank_transaction.py
+++ b/erpnext/accounts/doctype/bank_transaction/bank_transaction.py
@@ -1,9 +1,6 @@
 # Copyright (c) 2019, Frappe Technologies Pvt. Ltd. and contributors
 # For license information, please see license.txt
 
-
-from functools import reduce
-
 import frappe
 from frappe.utils import flt
 
@@ -18,72 +15,137 @@
 		self.clear_linked_payment_entries()
 		self.set_status()
 
+	_saving_flag = False
+
+	# nosemgrep: frappe-semgrep-rules.rules.frappe-modifying-but-not-comitting
 	def on_update_after_submit(self):
-		self.update_allocations()
-		self.clear_linked_payment_entries()
-		self.set_status(update=True)
+		"Run on save(). Avoid recursion caused by multiple saves"
+		if not self._saving_flag:
+			self._saving_flag = True
+			self.clear_linked_payment_entries()
+			self.update_allocations()
+			self._saving_flag = False
 
 	def on_cancel(self):
 		self.clear_linked_payment_entries(for_cancel=True)
 		self.set_status(update=True)
 
 	def update_allocations(self):
+		"The doctype does not allow modifications after submission, so write to the db direct"
 		if self.payment_entries:
-			allocated_amount = reduce(
-				lambda x, y: flt(x) + flt(y), [x.allocated_amount for x in self.payment_entries]
-			)
+			allocated_amount = sum(p.allocated_amount for p in self.payment_entries)
 		else:
-			allocated_amount = 0
+			allocated_amount = 0.0
 
-		if allocated_amount:
-			frappe.db.set_value(self.doctype, self.name, "allocated_amount", flt(allocated_amount))
-			frappe.db.set_value(
-				self.doctype,
-				self.name,
-				"unallocated_amount",
-				abs(flt(self.withdrawal) - flt(self.deposit)) - flt(allocated_amount),
-			)
+		amount = abs(flt(self.withdrawal) - flt(self.deposit))
+		self.db_set("allocated_amount", flt(allocated_amount))
+		self.db_set("unallocated_amount", amount - flt(allocated_amount))
+		self.reload()
+		self.set_status(update=True)
 
-		else:
-			frappe.db.set_value(self.doctype, self.name, "allocated_amount", 0)
-			frappe.db.set_value(
-				self.doctype, self.name, "unallocated_amount", abs(flt(self.withdrawal) - flt(self.deposit))
-			)
+	def add_payment_entries(self, vouchers):
+		"Add the vouchers with zero allocation. Save() will perform the allocations and clearance"
+		if 0.0 >= self.unallocated_amount:
+			frappe.throw(frappe._(f"Bank Transaction {self.name} is already fully reconciled"))
 
-		amount = self.deposit or self.withdrawal
-		if amount == self.allocated_amount:
-			frappe.db.set_value(self.doctype, self.name, "status", "Reconciled")
+		added = False
+		for voucher in vouchers:
+			# Can't add same voucher twice
+			found = False
+			for pe in self.payment_entries:
+				if (
+					pe.payment_document == voucher["payment_doctype"]
+					and pe.payment_entry == voucher["payment_name"]
+				):
+					found = True
+
+			if not found:
+				pe = {
+					"payment_document": voucher["payment_doctype"],
+					"payment_entry": voucher["payment_name"],
+					"allocated_amount": 0.0,  # Temporary
+				}
+				child = self.append("payment_entries", pe)
+				added = True
+
+		# runs on_update_after_submit
+		if added:
+			self.save()
+
+	def allocate_payment_entries(self):
+		"""Refactored from bank reconciliation tool.
+		Non-zero allocations must be amended/cleared manually
+		Get the bank transaction amount (b) and remove as we allocate
+		For each payment_entry if allocated_amount == 0:
+		- get the amount already allocated against all transactions (t), need latest date
+		- get the voucher amount (from gl) (v)
+		- allocate (a = v - t)
+		    - a = 0: should already be cleared, so clear & remove payment_entry
+		    - 0 < a <= u: allocate a & clear
+		    - 0 < a, a > u: allocate u
+		    - 0 > a: Error: already over-allocated
+		- clear means: set the latest transaction date as clearance date
+		"""
+		gl_bank_account = frappe.db.get_value("Bank Account", self.bank_account, "account")
+		remaining_amount = self.unallocated_amount
+		for payment_entry in self.payment_entries:
+			if payment_entry.allocated_amount == 0.0:
+				unallocated_amount, should_clear, latest_transaction = get_clearance_details(
+					self, payment_entry
+				)
+
+				if 0.0 == unallocated_amount:
+					if should_clear:
+						latest_transaction.clear_linked_payment_entry(payment_entry)
+					self.db_delete_payment_entry(payment_entry)
+
+				elif remaining_amount <= 0.0:
+					self.db_delete_payment_entry(payment_entry)
+
+				elif 0.0 < unallocated_amount and unallocated_amount <= remaining_amount:
+					payment_entry.db_set("allocated_amount", unallocated_amount)
+					remaining_amount -= unallocated_amount
+					if should_clear:
+						latest_transaction.clear_linked_payment_entry(payment_entry)
+
+				elif 0.0 < unallocated_amount and unallocated_amount > remaining_amount:
+					payment_entry.db_set("allocated_amount", remaining_amount)
+					remaining_amount = 0.0
+
+				elif 0.0 > unallocated_amount:
+					self.db_delete_payment_entry(payment_entry)
+					frappe.throw(
+						frappe._(f"Voucher {payment_entry.payment_entry} is over-allocated by {unallocated_amount}")
+					)
 
 		self.reload()
 
-	def clear_linked_payment_entries(self, for_cancel=False):
+	def db_delete_payment_entry(self, payment_entry):
+		frappe.db.delete("Bank Transaction Payments", {"name": payment_entry.name})
+
+	@frappe.whitelist()
+	def remove_payment_entries(self):
 		for payment_entry in self.payment_entries:
-			if payment_entry.payment_document == "Sales Invoice":
-				self.clear_sales_invoice(payment_entry, for_cancel=for_cancel)
-			elif payment_entry.payment_document in get_doctypes_for_bank_reconciliation():
-				self.clear_simple_entry(payment_entry, for_cancel=for_cancel)
+			self.remove_payment_entry(payment_entry)
+		# runs on_update_after_submit
+		self.save()
 
-	def clear_simple_entry(self, payment_entry, for_cancel=False):
-		if payment_entry.payment_document == "Payment Entry":
-			if (
-				frappe.db.get_value("Payment Entry", payment_entry.payment_entry, "payment_type")
-				== "Internal Transfer"
-			):
-				if len(get_reconciled_bank_transactions(payment_entry)) < 2:
-					return
+	def remove_payment_entry(self, payment_entry):
+		"Clear payment entry and clearance"
+		self.clear_linked_payment_entry(payment_entry, for_cancel=True)
+		self.remove(payment_entry)
 
-		clearance_date = self.date if not for_cancel else None
-		frappe.db.set_value(
-			payment_entry.payment_document, payment_entry.payment_entry, "clearance_date", clearance_date
-		)
+	def clear_linked_payment_entries(self, for_cancel=False):
+		if for_cancel:
+			for payment_entry in self.payment_entries:
+				self.clear_linked_payment_entry(payment_entry, for_cancel)
+		else:
+			self.allocate_payment_entries()
 
-	def clear_sales_invoice(self, payment_entry, for_cancel=False):
-		clearance_date = self.date if not for_cancel else None
-		frappe.db.set_value(
-			"Sales Invoice Payment",
-			dict(parenttype=payment_entry.payment_document, parent=payment_entry.payment_entry),
-			"clearance_date",
-			clearance_date,
+	def clear_linked_payment_entry(self, payment_entry, for_cancel=False):
+		clearance_date = None if for_cancel else self.date
+		set_voucher_clearance(
+			payment_entry.payment_document, payment_entry.payment_entry, clearance_date, self
 		)
 
 
@@ -93,38 +155,112 @@
 	return frappe.get_hooks("bank_reconciliation_doctypes")
 
 
-def get_reconciled_bank_transactions(payment_entry):
-	reconciled_bank_transactions = frappe.get_all(
-		"Bank Transaction Payments",
-		filters={"payment_entry": payment_entry.payment_entry},
-		fields=["parent"],
+def get_clearance_details(transaction, payment_entry):
+	"""
+	There should only be one bank gle for a voucher.
+	Could be none for a Bank Transaction.
+	But if a JE, could affect two banks.
+	Should only clear the voucher if all bank gles are allocated.
+	"""
+	gl_bank_account = frappe.db.get_value("Bank Account", transaction.bank_account, "account")
+	gles = get_related_bank_gl_entries(payment_entry.payment_document, payment_entry.payment_entry)
+	bt_allocations = get_total_allocated_amount(
+		payment_entry.payment_document, payment_entry.payment_entry
 	)
 
-	return reconciled_bank_transactions
+	unallocated_amount = min(
+		transaction.unallocated_amount,
+		get_paid_amount(payment_entry, transaction.currency, gl_bank_account),
+	)
+	unmatched_gles = len(gles)
+	latest_transaction = transaction
+	for gle in gles:
+		if gle["gl_account"] == gl_bank_account:
+			if gle["amount"] <= 0.0:
+				frappe.throw(
+					frappe._(f"Voucher {payment_entry.payment_entry} value is broken: {gle['amount']}")
+				)
+
+			unmatched_gles -= 1
+			unallocated_amount = gle["amount"]
+			for a in bt_allocations:
+				if a["gl_account"] == gle["gl_account"]:
+					unallocated_amount = gle["amount"] - a["total"]
+					if frappe.utils.getdate(transaction.date) < a["latest_date"]:
+						latest_transaction = frappe.get_doc("Bank Transaction", a["latest_name"])
+		else:
+			# Must be a Journal Entry affecting more than one bank
+			for a in bt_allocations:
+				if a["gl_account"] == gle["gl_account"] and a["total"] == gle["amount"]:
+					unmatched_gles -= 1
+
+	return unallocated_amount, unmatched_gles == 0, latest_transaction
 
 
-def get_total_allocated_amount(payment_entry):
-	return frappe.db.sql(
+def get_related_bank_gl_entries(doctype, docname):
+	# nosemgrep: frappe-semgrep-rules.rules.frappe-using-db-sql
+	result = frappe.db.sql(
 		"""
 		SELECT
-			SUM(btp.allocated_amount) as allocated_amount,
-			bt.name
+			ABS(gle.credit_in_account_currency - gle.debit_in_account_currency) AS amount,
+			gle.account AS gl_account
 		FROM
-			`tabBank Transaction Payments` as btp
+			`tabGL Entry` gle
 		LEFT JOIN
-			`tabBank Transaction` bt ON bt.name=btp.parent
+			`tabAccount` ac ON ac.name=gle.account
 		WHERE
-			btp.payment_document = %s
-		AND
-			btp.payment_entry = %s
-		AND
-			bt.docstatus = 1""",
-		(payment_entry.payment_document, payment_entry.payment_entry),
+			ac.account_type = 'Bank'
+			AND gle.voucher_type = %(doctype)s
+			AND gle.voucher_no = %(docname)s
+			AND is_cancelled = 0
+		""",
+		dict(doctype=doctype, docname=docname),
 		as_dict=True,
 	)
+	return result
 
 
-def get_paid_amount(payment_entry, currency, bank_account):
+def get_total_allocated_amount(doctype, docname):
+	"""
+	Gets the sum of allocations for a voucher on each bank GL account
+	along with the latest bank transaction name & date
+	NOTE: query may also include just saved vouchers/payments but with zero allocated_amount
+	"""
+	# nosemgrep: frappe-semgrep-rules.rules.frappe-using-db-sql
+	result = frappe.db.sql(
+		"""
+		SELECT total, latest_name, latest_date, gl_account FROM (
+			SELECT
+				ROW_NUMBER() OVER w AS rownum,
+				SUM(btp.allocated_amount) OVER(PARTITION BY ba.account) AS total,
+				FIRST_VALUE(bt.name) OVER w AS latest_name,
+				FIRST_VALUE(bt.date) OVER w AS latest_date,
+				ba.account AS gl_account
+			FROM
+				`tabBank Transaction Payments` btp
+			LEFT JOIN `tabBank Transaction` bt ON bt.name=btp.parent
+			LEFT JOIN `tabBank Account` ba ON ba.name=bt.bank_account
+			WHERE
+				btp.payment_document = %(doctype)s
+				AND btp.payment_entry = %(docname)s
+				AND bt.docstatus = 1
+			WINDOW w AS (PARTITION BY ba.account ORDER BY bt.date desc)
+		) temp
+		WHERE
+			rownum = 1
+		""",
+		dict(doctype=doctype, docname=docname),
+		as_dict=True,
+	)
+	for row in result:
+		# Why is this *sometimes* a byte string?
+		if isinstance(row["latest_name"], bytes):
+			row["latest_name"] = row["latest_name"].decode()
+		row["latest_date"] = frappe.utils.getdate(row["latest_date"])
+	return result
+
+
+def get_paid_amount(payment_entry, currency, gl_bank_account):
 	if payment_entry.payment_document in ["Payment Entry", "Sales Invoice", "Purchase Invoice"]:
 
 		paid_amount_field = "paid_amount"
@@ -147,7 +283,7 @@
 	elif payment_entry.payment_document == "Journal Entry":
 		return frappe.db.get_value(
 			"Journal Entry Account",
-			{"parent": payment_entry.payment_entry, "account": bank_account},
+			{"parent": payment_entry.payment_entry, "account": gl_bank_account},
 			"sum(credit_in_account_currency)",
 		)
 
@@ -166,6 +302,12 @@
 			payment_entry.payment_document, payment_entry.payment_entry, "amount_paid"
 		)
 
+	elif payment_entry.payment_document == "Bank Transaction":
+		dep, wth = frappe.db.get_value(
+			"Bank Transaction", payment_entry.payment_entry, ("deposit", "withdrawal")
+		)
+		return abs(flt(wth) - flt(dep))
+
 	else:
 		frappe.throw(
 			"Please reconcile {0}: {1} manually".format(
@@ -174,18 +316,55 @@
 		)
 
 
-@frappe.whitelist()
-def unclear_reference_payment(doctype, docname):
-	if frappe.db.exists(doctype, docname):
-		doc = frappe.get_doc(doctype, docname)
-		if doctype == "Sales Invoice":
-			frappe.db.set_value(
-				"Sales Invoice Payment",
-				dict(parenttype=doc.payment_document, parent=doc.payment_entry),
-				"clearance_date",
-				None,
-			)
-		else:
-			frappe.db.set_value(doc.payment_document, doc.payment_entry, "clearance_date", None)
+def set_voucher_clearance(doctype, docname, clearance_date, self):
+	if doctype in [
+		"Payment Entry",
+		"Journal Entry",
+		"Purchase Invoice",
+		"Expense Claim",
+		"Loan Repayment",
+		"Loan Disbursement",
+	]:
+		if (
+			doctype == "Payment Entry"
+			and frappe.db.get_value("Payment Entry", docname, "payment_type") == "Internal Transfer"
+			and len(get_reconciled_bank_transactions(doctype, docname)) < 2
+		):
+			return
+		frappe.db.set_value(doctype, docname, "clearance_date", clearance_date)
 
-		return doc.payment_entry
+	elif doctype == "Sales Invoice":
+		frappe.db.set_value(
+			"Sales Invoice Payment",
+			dict(parenttype=doctype, parent=docname),
+			"clearance_date",
+			clearance_date,
+		)
+
+	elif doctype == "Bank Transaction":
+		# For when a second bank transaction has fixed another, e.g. refund
+		bt = frappe.get_doc(doctype, docname)
+		if clearance_date:
+			vouchers = [{"payment_doctype": "Bank Transaction", "payment_name": self.name}]
+			bt.add_payment_entries(vouchers)
+		else:
+			for pe in bt.payment_entries:
+				if pe.payment_document == self.doctype and pe.payment_entry == self.name:
+					bt.remove(pe)
+					bt.save()
+					break
+
+
+def get_reconciled_bank_transactions(doctype, docname):
+	return frappe.get_all(
+		"Bank Transaction Payments",
+		filters={"payment_document": doctype, "payment_entry": docname},
+		pluck="parent",
+	)
+
+
+@frappe.whitelist()
+def unclear_reference_payment(doctype, docname, bt_name):
+	bt = frappe.get_doc("Bank Transaction", bt_name)
+	set_voucher_clearance(doctype, docname, None, bt)
+	return docname
diff --git a/erpnext/accounts/doctype/journal_entry/journal_entry.js b/erpnext/accounts/doctype/journal_entry/journal_entry.js
index 21f27ae..089f20b 100644
--- a/erpnext/accounts/doctype/journal_entry/journal_entry.js
+++ b/erpnext/accounts/doctype/journal_entry/journal_entry.js
@@ -8,7 +8,7 @@
 frappe.ui.form.on("Journal Entry", {
 	setup: function(frm) {
 		frm.add_fetch("bank_account", "account", "account");
-		frm.ignore_doctypes_on_cancel_all = ['Sales Invoice', 'Purchase Invoice', 'Journal Entry'];
+		frm.ignore_doctypes_on_cancel_all = ['Sales Invoice', 'Purchase Invoice', 'Journal Entry', "Repost Payment Ledger"];
 	},
 
 	refresh: function(frm) {
diff --git a/erpnext/accounts/doctype/journal_entry/journal_entry.py b/erpnext/accounts/doctype/journal_entry/journal_entry.py
index 5b0322a..db399b7 100644
--- a/erpnext/accounts/doctype/journal_entry/journal_entry.py
+++ b/erpnext/accounts/doctype/journal_entry/journal_entry.py
@@ -89,7 +89,13 @@
 		from erpnext.accounts.utils import unlink_ref_doc_from_payment_entries
 
 		unlink_ref_doc_from_payment_entries(self)
-		self.ignore_linked_doctypes = ("GL Entry", "Stock Ledger Entry", "Payment Ledger Entry")
+		self.ignore_linked_doctypes = (
+			"GL Entry",
+			"Stock Ledger Entry",
+			"Payment Ledger Entry",
+			"Repost Payment Ledger",
+			"Repost Payment Ledger Items",
+		)
 		self.make_gl_entries(1)
 		self.update_advance_paid()
 		self.unlink_advance_entry_reference()
@@ -238,21 +244,16 @@
 			):
 				processed_assets.append(d.reference_name)
 
-				asset = frappe.db.get_value(
-					"Asset", d.reference_name, ["calculate_depreciation", "value_after_depreciation"], as_dict=1
-				)
+				asset = frappe.get_doc("Asset", d.reference_name)
 
 				if asset.calculate_depreciation:
 					continue
 
 				depr_value = d.debit or d.credit
 
-				frappe.db.set_value(
-					"Asset",
-					d.reference_name,
-					"value_after_depreciation",
-					asset.value_after_depreciation - depr_value,
-				)
+				asset.db_set("value_after_depreciation", asset.value_after_depreciation - depr_value)
+
+				asset.set_status()
 
 	def update_inter_company_jv(self):
 		if (
@@ -348,12 +349,9 @@
 				else:
 					depr_value = d.debit or d.credit
 
-					frappe.db.set_value(
-						"Asset",
-						d.reference_name,
-						"value_after_depreciation",
-						asset.value_after_depreciation + depr_value,
-					)
+					asset.db_set("value_after_depreciation", asset.value_after_depreciation + depr_value)
+
+					asset.set_status()
 
 	def unlink_inter_company_jv(self):
 		if (
diff --git a/erpnext/accounts/doctype/payment_entry/payment_entry.js b/erpnext/accounts/doctype/payment_entry/payment_entry.js
index 6039bdf..91374ae 100644
--- a/erpnext/accounts/doctype/payment_entry/payment_entry.js
+++ b/erpnext/accounts/doctype/payment_entry/payment_entry.js
@@ -7,7 +7,7 @@
 
 frappe.ui.form.on('Payment Entry', {
 	onload: function(frm) {
-		frm.ignore_doctypes_on_cancel_all = ['Sales Invoice', 'Purchase Invoice'];
+		frm.ignore_doctypes_on_cancel_all = ['Sales Invoice', 'Purchase Invoice', "Repost Payment Ledger"];
 
 		if(frm.doc.__islocal) {
 			if (!frm.doc.paid_from) frm.set_value("paid_from_account_currency", null);
diff --git a/erpnext/accounts/doctype/payment_entry/payment_entry.json b/erpnext/accounts/doctype/payment_entry/payment_entry.json
index 4a7a57b..3927eca 100644
--- a/erpnext/accounts/doctype/payment_entry/payment_entry.json
+++ b/erpnext/accounts/doctype/payment_entry/payment_entry.json
@@ -239,7 +239,7 @@
    "depends_on": "paid_from",
    "fieldname": "paid_from_account_currency",
    "fieldtype": "Link",
-   "label": "Account Currency",
+   "label": "Account Currency (From)",
    "options": "Currency",
    "print_hide": 1,
    "read_only": 1,
@@ -249,7 +249,7 @@
    "depends_on": "paid_from",
    "fieldname": "paid_from_account_balance",
    "fieldtype": "Currency",
-   "label": "Account Balance",
+   "label": "Account Balance (From)",
    "options": "paid_from_account_currency",
    "print_hide": 1,
    "read_only": 1
@@ -272,7 +272,7 @@
    "depends_on": "paid_to",
    "fieldname": "paid_to_account_currency",
    "fieldtype": "Link",
-   "label": "Account Currency",
+   "label": "Account Currency (To)",
    "options": "Currency",
    "print_hide": 1,
    "read_only": 1,
@@ -282,7 +282,7 @@
    "depends_on": "paid_to",
    "fieldname": "paid_to_account_balance",
    "fieldtype": "Currency",
-   "label": "Account Balance",
+   "label": "Account Balance (To)",
    "options": "paid_to_account_currency",
    "print_hide": 1,
    "read_only": 1
@@ -304,7 +304,7 @@
   {
    "fieldname": "source_exchange_rate",
    "fieldtype": "Float",
-   "label": "Exchange Rate",
+   "label": "Source Exchange Rate",
    "precision": "9",
    "print_hide": 1,
    "reqd": 1
@@ -334,7 +334,7 @@
   {
    "fieldname": "target_exchange_rate",
    "fieldtype": "Float",
-   "label": "Exchange Rate",
+   "label": "Target Exchange Rate",
    "precision": "9",
    "print_hide": 1,
    "reqd": 1
@@ -633,14 +633,14 @@
    "depends_on": "eval:doc.party_type == 'Supplier'",
    "fieldname": "purchase_taxes_and_charges_template",
    "fieldtype": "Link",
-   "label": "Taxes and Charges Template",
+   "label": "Purchase Taxes and Charges Template",
    "options": "Purchase Taxes and Charges Template"
   },
   {
    "depends_on": "eval: doc.party_type == 'Customer'",
    "fieldname": "sales_taxes_and_charges_template",
    "fieldtype": "Link",
-   "label": "Taxes and Charges Template",
+   "label": "Sales Taxes and Charges Template",
    "options": "Sales Taxes and Charges Template"
   },
   {
@@ -733,7 +733,7 @@
  "index_web_pages_for_search": 1,
  "is_submittable": 1,
  "links": [],
- "modified": "2022-12-08 16:25:43.824051",
+ "modified": "2023-02-14 04:52:30.478523",
  "modified_by": "Administrator",
  "module": "Accounts",
  "name": "Payment Entry",
diff --git a/erpnext/accounts/doctype/payment_entry/payment_entry.py b/erpnext/accounts/doctype/payment_entry/payment_entry.py
index 1cccbd9..cd5b6d5 100644
--- a/erpnext/accounts/doctype/payment_entry/payment_entry.py
+++ b/erpnext/accounts/doctype/payment_entry/payment_entry.py
@@ -92,7 +92,13 @@
 		self.set_status()
 
 	def on_cancel(self):
-		self.ignore_linked_doctypes = ("GL Entry", "Stock Ledger Entry", "Payment Ledger Entry")
+		self.ignore_linked_doctypes = (
+			"GL Entry",
+			"Stock Ledger Entry",
+			"Payment Ledger Entry",
+			"Repost Payment Ledger",
+			"Repost Payment Ledger Items",
+		)
 		self.make_gl_entries(cancel=1)
 		self.update_outstanding_amounts()
 		self.update_advance_paid()
diff --git a/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.py b/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.py
index 675a328..e3d9c26 100644
--- a/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.py
+++ b/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.py
@@ -368,6 +368,7 @@
 				"exchange_rate": 1,
 				"cost_center": erpnext.get_default_cost_center(self.company),
 				reverse_dr_or_cr + "_in_account_currency": flt(row.difference_amount),
+				reverse_dr_or_cr: flt(row.difference_amount),
 			}
 		)
 
diff --git a/erpnext/accounts/doctype/payment_request/payment_request.py b/erpnext/accounts/doctype/payment_request/payment_request.py
index fc837c7..2f43914 100644
--- a/erpnext/accounts/doctype/payment_request/payment_request.py
+++ b/erpnext/accounts/doctype/payment_request/payment_request.py
@@ -45,21 +45,20 @@
 			frappe.throw(_("To create a Payment Request reference document is required"))
 
 	def validate_payment_request_amount(self):
-		existing_payment_request_amount = get_existing_payment_request_amount(
-			self.reference_doctype, self.reference_name
+		existing_payment_request_amount = flt(
+			get_existing_payment_request_amount(self.reference_doctype, self.reference_name)
 		)
 
-		if existing_payment_request_amount:
-			ref_doc = frappe.get_doc(self.reference_doctype, self.reference_name)
-			if not hasattr(ref_doc, "order_type") or getattr(ref_doc, "order_type") != "Shopping Cart":
-				ref_amount = get_amount(ref_doc, self.payment_account)
+		ref_doc = frappe.get_doc(self.reference_doctype, self.reference_name)
+		if not hasattr(ref_doc, "order_type") or getattr(ref_doc, "order_type") != "Shopping Cart":
+			ref_amount = get_amount(ref_doc, self.payment_account)
 
-				if existing_payment_request_amount + flt(self.grand_total) > ref_amount:
-					frappe.throw(
-						_("Total Payment Request amount cannot be greater than {0} amount").format(
-							self.reference_doctype
-						)
+			if existing_payment_request_amount + flt(self.grand_total) > ref_amount:
+				frappe.throw(
+					_("Total Payment Request amount cannot be greater than {0} amount").format(
+						self.reference_doctype
 					)
+				)
 
 	def validate_currency(self):
 		ref_doc = frappe.get_doc(self.reference_doctype, self.reference_name)
@@ -496,7 +495,7 @@
 	"""get amount based on doctype"""
 	dt = ref_doc.doctype
 	if dt in ["Sales Order", "Purchase Order"]:
-		grand_total = flt(ref_doc.grand_total) - flt(ref_doc.advance_paid)
+		grand_total = flt(ref_doc.rounded_total) - flt(ref_doc.advance_paid)
 
 	elif dt in ["Sales Invoice", "Purchase Invoice"]:
 		if ref_doc.party_account_currency == ref_doc.currency:
diff --git a/erpnext/accounts/doctype/pos_closing_entry/pos_closing_entry.py b/erpnext/accounts/doctype/pos_closing_entry/pos_closing_entry.py
index 655c4ec..115b415 100644
--- a/erpnext/accounts/doctype/pos_closing_entry/pos_closing_entry.py
+++ b/erpnext/accounts/doctype/pos_closing_entry/pos_closing_entry.py
@@ -21,8 +21,24 @@
 		if frappe.db.get_value("POS Opening Entry", self.pos_opening_entry, "status") != "Open":
 			frappe.throw(_("Selected POS Opening Entry should be open."), title=_("Invalid Opening Entry"))
 
+		self.validate_duplicate_pos_invoices()
 		self.validate_pos_invoices()
 
+	def validate_duplicate_pos_invoices(self):
+		pos_occurences = {}
+		for idx, inv in enumerate(self.pos_transactions, 1):
+			pos_occurences.setdefault(inv.pos_invoice, []).append(idx)
+
+		error_list = []
+		for key, value in pos_occurences.items():
+			if len(value) > 1:
+				error_list.append(
+					_("{} is added multiple times on rows: {}".format(frappe.bold(key), frappe.bold(value)))
+				)
+
+		if error_list:
+			frappe.throw(error_list, title=_("Duplicate POS Invoices found"), as_list=True)
+
 	def validate_pos_invoices(self):
 		invalid_rows = []
 		for d in self.pos_transactions:
diff --git a/erpnext/accounts/doctype/pos_invoice_merge_log/pos_invoice_merge_log.py b/erpnext/accounts/doctype/pos_invoice_merge_log/pos_invoice_merge_log.py
index 3a237a4..b1e2208 100644
--- a/erpnext/accounts/doctype/pos_invoice_merge_log/pos_invoice_merge_log.py
+++ b/erpnext/accounts/doctype/pos_invoice_merge_log/pos_invoice_merge_log.py
@@ -17,6 +17,22 @@
 	def validate(self):
 		self.validate_customer()
 		self.validate_pos_invoice_status()
+		self.validate_duplicate_pos_invoices()
+
+	def validate_duplicate_pos_invoices(self):
+		pos_occurences = {}
+		for idx, inv in enumerate(self.pos_invoices, 1):
+			pos_occurences.setdefault(inv.pos_invoice, []).append(idx)
+
+		error_list = []
+		for key, value in pos_occurences.items():
+			if len(value) > 1:
+				error_list.append(
+					_("{} is added multiple times on rows: {}".format(frappe.bold(key), frappe.bold(value)))
+				)
+
+		if error_list:
+			frappe.throw(error_list, title=_("Duplicate POS Invoices found"), as_list=True)
 
 	def validate_customer(self):
 		if self.merge_invoices_based_on == "Customer Group":
@@ -425,6 +441,8 @@
 
 		if closing_entry:
 			closing_entry.set_status(update=True, status="Failed")
+			if type(error_message) == list:
+				error_message = frappe.json.dumps(error_message)
 			closing_entry.db_set("error_message", error_message)
 		raise
 
diff --git a/erpnext/accounts/doctype/pricing_rule/pricing_rule.json b/erpnext/accounts/doctype/pricing_rule/pricing_rule.json
index ce9ce64..a63039e 100644
--- a/erpnext/accounts/doctype/pricing_rule/pricing_rule.json
+++ b/erpnext/accounts/doctype/pricing_rule/pricing_rule.json
@@ -472,7 +472,7 @@
    "description": "If rate is zero them item will be treated as \"Free Item\"",
    "fieldname": "free_item_rate",
    "fieldtype": "Currency",
-   "label": "Rate"
+   "label": "Free Item Rate"
   },
   {
    "collapsible": 1,
@@ -608,7 +608,7 @@
  "icon": "fa fa-gift",
  "idx": 1,
  "links": [],
- "modified": "2022-10-13 19:05:35.056304",
+ "modified": "2023-02-14 04:53:34.887358",
  "modified_by": "Administrator",
  "module": "Accounts",
  "name": "Pricing Rule",
diff --git a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js
index a098e8d..e2b4a1a 100644
--- a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js
+++ b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js
@@ -31,7 +31,7 @@
 		super.onload();
 
 		// Ignore linked advances
-		this.frm.ignore_doctypes_on_cancel_all = ['Journal Entry', 'Payment Entry', 'Purchase Invoice'];
+		this.frm.ignore_doctypes_on_cancel_all = ['Journal Entry', 'Payment Entry', 'Purchase Invoice', "Repost Payment Ledger"];
 
 		if(!this.frm.doc.__islocal) {
 			// show credit_to in print format
diff --git a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py
index 0e9f976..21addab 100644
--- a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py
+++ b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py
@@ -5,6 +5,7 @@
 import frappe
 from frappe import _, throw
 from frappe.model.mapper import get_mapped_doc
+from frappe.query_builder.functions import Sum
 from frappe.utils import cint, cstr, flt, formatdate, get_link_to_form, getdate, nowdate
 
 import erpnext
@@ -1416,6 +1417,8 @@
 			"GL Entry",
 			"Stock Ledger Entry",
 			"Repost Item Valuation",
+			"Repost Payment Ledger",
+			"Repost Payment Ledger Items",
 			"Payment Ledger Entry",
 			"Tax Withheld Vouchers",
 		)
@@ -1463,19 +1466,16 @@
 	def update_billing_status_in_pr(self, update_modified=True):
 		updated_pr = []
 		po_details = []
+
+		pr_details_billed_amt = self.get_pr_details_billed_amt()
+
 		for d in self.get("items"):
 			if d.pr_detail:
-				billed_amt = frappe.db.sql(
-					"""select sum(amount) from `tabPurchase Invoice Item`
-					where pr_detail=%s and docstatus=1""",
-					d.pr_detail,
-				)
-				billed_amt = billed_amt and billed_amt[0][0] or 0
 				frappe.db.set_value(
 					"Purchase Receipt Item",
 					d.pr_detail,
 					"billed_amt",
-					billed_amt,
+					flt(pr_details_billed_amt.get(d.pr_detail)),
 					update_modified=update_modified,
 				)
 				updated_pr.append(d.purchase_receipt)
@@ -1491,6 +1491,24 @@
 			pr_doc = frappe.get_doc("Purchase Receipt", pr)
 			update_billing_percentage(pr_doc, update_modified=update_modified)
 
+	def get_pr_details_billed_amt(self):
+		# Get billed amount based on purchase receipt item reference (pr_detail) in purchase invoice
+
+		pr_details_billed_amt = {}
+		pr_details = [d.get("pr_detail") for d in self.get("items") if d.get("pr_detail")]
+		if pr_details:
+			doctype = frappe.qb.DocType("Purchase Invoice Item")
+			query = (
+				frappe.qb.from_(doctype)
+				.select(doctype.pr_detail, Sum(doctype.amount))
+				.where(doctype.pr_detail.isin(pr_details) & doctype.docstatus == 1)
+				.groupby(doctype.pr_detail)
+			)
+
+			pr_details_billed_amt = frappe._dict(query.run(as_list=1))
+
+		return pr_details_billed_amt
+
 	def on_recurring(self, reference_doc, auto_repeat_doc):
 		self.due_date = None
 
diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.js b/erpnext/accounts/doctype/sales_invoice/sales_invoice.js
index 7abf3f3..47e3f9b 100644
--- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.js
+++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.js
@@ -34,7 +34,7 @@
 		super.onload();
 
 		this.frm.ignore_doctypes_on_cancel_all = ['POS Invoice', 'Timesheet', 'POS Invoice Merge Log',
-			'POS Closing Entry', 'Journal Entry', 'Payment Entry'];
+							  'POS Closing Entry', 'Journal Entry', 'Payment Entry', "Repost Payment Ledger"];
 
 		if(!this.frm.doc.__islocal && !this.frm.doc.customer && this.frm.doc.debit_to) {
 			// show debit_to in print format
diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py
index 31cf120..5cda276 100644
--- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py
+++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py
@@ -397,6 +397,8 @@
 			"GL Entry",
 			"Stock Ledger Entry",
 			"Repost Item Valuation",
+			"Repost Payment Ledger",
+			"Repost Payment Ledger Items",
 			"Payment Ledger Entry",
 		)
 
diff --git a/erpnext/accounts/doctype/tax_withholding_category/tax_withholding_category.py b/erpnext/accounts/doctype/tax_withholding_category/tax_withholding_category.py
index 2c829b2..f0146ea 100644
--- a/erpnext/accounts/doctype/tax_withholding_category/tax_withholding_category.py
+++ b/erpnext/accounts/doctype/tax_withholding_category/tax_withholding_category.py
@@ -278,7 +278,7 @@
 			tax_amount = get_tcs_amount(parties, inv, tax_details, vouchers, advance_vouchers)
 
 	if cint(tax_details.round_off_tax_amount):
-		tax_amount = round(tax_amount)
+		tax_amount = normal_round(tax_amount)
 
 	return tax_amount, tax_deducted, tax_deducted_on_advances, voucher_wise_amount
 
@@ -603,3 +603,20 @@
 		valid = True
 
 	return valid
+
+
+def normal_round(number):
+	"""
+	Rounds a number to the nearest integer.
+	:param number: The number to round.
+	"""
+	decimal_part = number - int(number)
+
+	if decimal_part >= 0.5:
+		decimal_part = 1
+	else:
+		decimal_part = 0
+
+	number = int(number) + decimal_part
+
+	return number
diff --git a/erpnext/accounts/report/asset_depreciations_and_balances/asset_depreciations_and_balances.py b/erpnext/accounts/report/asset_depreciations_and_balances/asset_depreciations_and_balances.py
index 43b95dc..5827697 100644
--- a/erpnext/accounts/report/asset_depreciations_and_balances/asset_depreciations_and_balances.py
+++ b/erpnext/accounts/report/asset_depreciations_and_balances/asset_depreciations_and_balances.py
@@ -136,6 +136,34 @@
 			group by a.asset_category
 			union
 			SELECT a.asset_category,
+				   ifnull(sum(case when gle.posting_date < %(from_date)s and (ifnull(a.disposal_date, 0) = 0 or a.disposal_date >= %(from_date)s) then
+								   gle.debit
+							  else
+								   0
+							  end), 0) as accumulated_depreciation_as_on_from_date,
+				   ifnull(sum(case when ifnull(a.disposal_date, 0) != 0 and a.disposal_date >= %(from_date)s
+										and a.disposal_date <= %(to_date)s and gle.posting_date <= a.disposal_date then
+								   gle.debit
+							  else
+								   0
+							  end), 0) as depreciation_eliminated_during_the_period,
+				   ifnull(sum(case when gle.posting_date >= %(from_date)s and gle.posting_date <= %(to_date)s
+										and (ifnull(a.disposal_date, 0) = 0 or gle.posting_date <= a.disposal_date) then
+								   gle.debit
+							  else
+								   0
+							  end), 0) as depreciation_amount_during_the_period
+			from `tabGL Entry` gle
+			join `tabAsset` a on
+				gle.against_voucher = a.name
+			join `tabAsset Category Account` aca on
+				aca.parent = a.asset_category and aca.company_name = %(company)s
+			join `tabCompany` company on
+				company.name = %(company)s
+			where a.docstatus=1 and a.company=%(company)s and a.calculate_depreciation=0 and a.purchase_date <= %(to_date)s and gle.debit != 0 and gle.is_cancelled = 0 and gle.account = ifnull(aca.depreciation_expense_account, company.depreciation_expense_account)
+			group by a.asset_category
+			union
+			SELECT a.asset_category,
 				   ifnull(sum(case when ifnull(a.disposal_date, 0) != 0 and (a.disposal_date < %(from_date)s or a.disposal_date > %(to_date)s) then
 									0
 							   else
diff --git a/erpnext/accounts/report/gross_profit/gross_profit.py b/erpnext/accounts/report/gross_profit/gross_profit.py
index e23265b..fde4de8 100644
--- a/erpnext/accounts/report/gross_profit/gross_profit.py
+++ b/erpnext/accounts/report/gross_profit/gross_profit.py
@@ -395,6 +395,7 @@
 
 class GrossProfitGenerator(object):
 	def __init__(self, filters=None):
+		self.sle = {}
 		self.data = []
 		self.average_buying_rate = {}
 		self.filters = frappe._dict(filters)
@@ -404,7 +405,6 @@
 		if filters.group_by == "Invoice":
 			self.group_items_by_invoice()
 
-		self.load_stock_ledger_entries()
 		self.load_product_bundle()
 		self.load_non_stock_items()
 		self.get_returned_invoice_items()
@@ -633,7 +633,7 @@
 			return flt(row.qty) * item_rate
 
 		else:
-			my_sle = self.sle.get((item_code, row.warehouse))
+			my_sle = self.get_stock_ledger_entries(item_code, row.warehouse)
 			if (row.update_stock or row.dn_detail) and my_sle:
 				parenttype, parent = row.parenttype, row.parent
 				if row.dn_detail:
@@ -651,7 +651,7 @@
 					dn["item_row"],
 					dn["warehouse"],
 				)
-				my_sle = self.sle.get((item_code, warehouse))
+				my_sle = self.get_stock_ledger_entries(item_code, row.warehouse)
 				return self.calculate_buying_amount_from_sle(
 					row, my_sle, parenttype, parent, item_row, item_code
 				)
@@ -667,15 +667,12 @@
 	def get_buying_amount_from_so_dn(self, sales_order, so_detail, item_code):
 		from frappe.query_builder.functions import Sum
 
-		delivery_note = frappe.qb.DocType("Delivery Note")
 		delivery_note_item = frappe.qb.DocType("Delivery Note Item")
 
 		query = (
-			frappe.qb.from_(delivery_note)
-			.inner_join(delivery_note_item)
-			.on(delivery_note.name == delivery_note_item.parent)
+			frappe.qb.from_(delivery_note_item)
 			.select(Sum(delivery_note_item.incoming_rate * delivery_note_item.stock_qty))
-			.where(delivery_note.docstatus == 1)
+			.where(delivery_note_item.docstatus == 1)
 			.where(delivery_note_item.item_code == item_code)
 			.where(delivery_note_item.against_sales_order == sales_order)
 			.where(delivery_note_item.so_detail == so_detail)
@@ -947,24 +944,36 @@
 			"Item", item_code, ["item_name", "description", "item_group", "brand"]
 		)
 
-	def load_stock_ledger_entries(self):
-		res = frappe.db.sql(
-			"""select item_code, voucher_type, voucher_no,
-				voucher_detail_no, stock_value, warehouse, actual_qty as qty
-			from `tabStock Ledger Entry`
-			where company=%(company)s and is_cancelled = 0
-			order by
-				item_code desc, warehouse desc, posting_date desc,
-				posting_time desc, creation desc""",
-			self.filters,
-			as_dict=True,
-		)
-		self.sle = {}
-		for r in res:
-			if (r.item_code, r.warehouse) not in self.sle:
-				self.sle[(r.item_code, r.warehouse)] = []
+	def get_stock_ledger_entries(self, item_code, warehouse):
+		if item_code and warehouse:
+			if (item_code, warehouse) not in self.sle:
+				sle = qb.DocType("Stock Ledger Entry")
+				res = (
+					qb.from_(sle)
+					.select(
+						sle.item_code,
+						sle.voucher_type,
+						sle.voucher_no,
+						sle.voucher_detail_no,
+						sle.stock_value,
+						sle.warehouse,
+						sle.actual_qty.as_("qty"),
+					)
+					.where(
+						(sle.company == self.filters.company)
+						& (sle.item_code == item_code)
+						& (sle.warehouse == warehouse)
+						& (sle.is_cancelled == 0)
+					)
+					.orderby(sle.item_code)
+					.orderby(sle.warehouse, sle.posting_date, sle.posting_time, sle.creation, order=Order.desc)
+					.run(as_dict=True)
+				)
 
-			self.sle[(r.item_code, r.warehouse)].append(r)
+				self.sle[(item_code, warehouse)] = res
+
+			return self.sle[(item_code, warehouse)]
+		return []
 
 	def load_product_bundle(self):
 		self.product_bundles = {}
diff --git a/erpnext/accounts/utils.py b/erpnext/accounts/utils.py
index a03de9e..2608c03 100644
--- a/erpnext/accounts/utils.py
+++ b/erpnext/accounts/utils.py
@@ -1512,9 +1512,12 @@
 		ref_doc = frappe.get_doc(voucher_type, voucher_no)
 
 		# Didn't use db_set for optimisation purpose
-		ref_doc.outstanding_amount = outstanding["outstanding_in_account_currency"]
+		ref_doc.outstanding_amount = outstanding["outstanding_in_account_currency"] or 0.0
 		frappe.db.set_value(
-			voucher_type, voucher_no, "outstanding_amount", outstanding["outstanding_in_account_currency"]
+			voucher_type,
+			voucher_no,
+			"outstanding_amount",
+			outstanding["outstanding_in_account_currency"] or 0.0,
 		)
 
 		ref_doc.set_status(update=True)
diff --git a/erpnext/assets/doctype/asset/asset.js b/erpnext/assets/doctype/asset/asset.js
index 4ed99f7..4951385 100644
--- a/erpnext/assets/doctype/asset/asset.js
+++ b/erpnext/assets/doctype/asset/asset.js
@@ -209,62 +209,62 @@
 			return
 		}
 
-		var x_intervals = [frm.doc.purchase_date];
+		var x_intervals = [frappe.format(frm.doc.purchase_date, { fieldtype: 'Date' })];
 		var asset_values = [frm.doc.gross_purchase_amount];
-		var last_depreciation_date = frm.doc.purchase_date;
 
-		if(frm.doc.opening_accumulated_depreciation) {
-			last_depreciation_date = frappe.datetime.add_months(frm.doc.next_depreciation_date,
-				-1*frm.doc.frequency_of_depreciation);
-
-			x_intervals.push(last_depreciation_date);
-			asset_values.push(flt(frm.doc.gross_purchase_amount) -
-				flt(frm.doc.opening_accumulated_depreciation));
-		}
 		if(frm.doc.calculate_depreciation) {
-			if (frm.doc.finance_books.length == 1) {
-				let depr_schedule = (await frappe.call(
-					"erpnext.assets.doctype.asset_depreciation_schedule.asset_depreciation_schedule.get_depr_schedule",
-					{
-						asset_name: frm.doc.name,
-						status: frm.doc.docstatus ? "Active" : "Draft",
-						finance_book: frm.doc.finance_books[0].finance_book || null
-					}
-				)).message;
-
-				$.each(depr_schedule || [], function(i, v) {
-					x_intervals.push(v.schedule_date);
-					var asset_value = flt(frm.doc.gross_purchase_amount) - flt(v.accumulated_depreciation_amount);
-					if(v.journal_entry) {
-						last_depreciation_date = v.schedule_date;
-						asset_values.push(asset_value);
-					} else {
-						if (in_list(["Scrapped", "Sold"], frm.doc.status)) {
-							asset_values.push(null);
-						} else {
-							asset_values.push(asset_value)
-						}
-					}
-				});
+			if(frm.doc.opening_accumulated_depreciation) {
+				var depreciation_date = frappe.datetime.add_months(
+					frm.doc.finance_books[0].depreciation_start_date,
+					-1 * frm.doc.finance_books[0].frequency_of_depreciation
+				);
+				x_intervals.push(frappe.format(depreciation_date, { fieldtype: 'Date' }));
+				asset_values.push(flt(frm.doc.gross_purchase_amount - frm.doc.opening_accumulated_depreciation, precision('gross_purchase_amount')));
 			}
+
+			let depr_schedule = (await frappe.call(
+				"erpnext.assets.doctype.asset_depreciation_schedule.asset_depreciation_schedule.get_depr_schedule",
+				{
+					asset_name: frm.doc.name,
+					status: frm.doc.docstatus ? "Active" : "Draft",
+					finance_book: frm.doc.finance_books[0].finance_book || null
+				}
+			)).message;
+
+			$.each(depr_schedule || [], function(i, v) {
+				x_intervals.push(frappe.format(v.schedule_date, { fieldtype: 'Date' }));
+				var asset_value = flt(frm.doc.gross_purchase_amount - v.accumulated_depreciation_amount, precision('gross_purchase_amount'));
+				if(v.journal_entry) {
+					asset_values.push(asset_value);
+				} else {
+					if (in_list(["Scrapped", "Sold"], frm.doc.status)) {
+						asset_values.push(null);
+					} else {
+						asset_values.push(asset_value)
+					}
+				}
+			});
 		} else {
+			if(frm.doc.opening_accumulated_depreciation) {
+				x_intervals.push(frappe.format(frm.doc.creation.split(" ")[0], { fieldtype: 'Date' }));
+				asset_values.push(flt(frm.doc.gross_purchase_amount - frm.doc.opening_accumulated_depreciation, precision('gross_purchase_amount')));
+			}
+
 			let depr_entries = (await frappe.call({
 				method: "get_manual_depreciation_entries",
 				doc: frm.doc,
 			})).message;
 
 			$.each(depr_entries || [], function(i, v) {
-				x_intervals.push(v.posting_date);
-				last_depreciation_date = v.posting_date;
+				x_intervals.push(frappe.format(v.posting_date, { fieldtype: 'Date' }));
 				let last_asset_value = asset_values[asset_values.length - 1]
-				asset_values.push(last_asset_value - v.value);
+				asset_values.push(flt(last_asset_value - v.value, precision('gross_purchase_amount')));
 			});
 		}
 
 		if(in_list(["Scrapped", "Sold"], frm.doc.status)) {
-			x_intervals.push(frm.doc.disposal_date);
+			x_intervals.push(frappe.format(frm.doc.disposal_date, { fieldtype: 'Date' }));
 			asset_values.push(0);
-			last_depreciation_date = frm.doc.disposal_date;
 		}
 
 		frm.dashboard.render_graph({
diff --git a/erpnext/assets/doctype/asset/asset.py b/erpnext/assets/doctype/asset/asset.py
index 4f1caca..e1d58a0 100644
--- a/erpnext/assets/doctype/asset/asset.py
+++ b/erpnext/assets/doctype/asset/asset.py
@@ -413,11 +413,14 @@
 
 			if self.journal_entry_for_scrap:
 				status = "Scrapped"
-			elif self.finance_books:
-				idx = self.get_default_finance_book_idx() or 0
+			else:
+				expected_value_after_useful_life = 0
+				value_after_depreciation = self.value_after_depreciation
 
-				expected_value_after_useful_life = self.finance_books[idx].expected_value_after_useful_life
-				value_after_depreciation = self.finance_books[idx].value_after_depreciation
+				if self.calculate_depreciation:
+					idx = self.get_default_finance_book_idx() or 0
+					expected_value_after_useful_life = self.finance_books[idx].expected_value_after_useful_life
+					value_after_depreciation = self.finance_books[idx].value_after_depreciation
 
 				if flt(value_after_depreciation) <= expected_value_after_useful_life:
 					status = "Fully Depreciated"
@@ -429,25 +432,16 @@
 
 	def get_value_after_depreciation(self, finance_book=None):
 		if not self.calculate_depreciation:
-			return self.value_after_depreciation
+			return flt(self.value_after_depreciation, self.precision("gross_purchase_amount"))
 
 		if not finance_book:
-			return self.get("finance_books")[0].value_after_depreciation
+			return flt(
+				self.get("finance_books")[0].value_after_depreciation, self.precision("gross_purchase_amount")
+			)
 
 		for row in self.get("finance_books"):
 			if finance_book == row.finance_book:
-				return row.value_after_depreciation
-
-	def _get_value_after_depreciation_for_making_schedule(self, fb_row):
-		# value_after_depreciation - current Asset value
-		if self.docstatus == 1 and fb_row.value_after_depreciation:
-			value_after_depreciation = flt(fb_row.value_after_depreciation)
-		else:
-			value_after_depreciation = flt(self.gross_purchase_amount) - flt(
-				self.opening_accumulated_depreciation
-			)
-
-		return value_after_depreciation
+				return flt(row.value_after_depreciation, self.precision("gross_purchase_amount"))
 
 	def get_default_finance_book_idx(self):
 		if not self.get("default_finance_book") and self.company:
@@ -472,6 +466,7 @@
 			.where(gle.debit != 0)
 			.where(gle.is_cancelled == 0)
 			.orderby(gle.posting_date)
+			.orderby(gle.creation)
 		).run(as_dict=True)
 
 		return records
diff --git a/erpnext/assets/doctype/asset/depreciation.py b/erpnext/assets/doctype/asset/depreciation.py
index e7a2532..fb6e174 100644
--- a/erpnext/assets/doctype/asset/depreciation.py
+++ b/erpnext/assets/doctype/asset/depreciation.py
@@ -168,7 +168,7 @@
 			row.value_after_depreciation -= d.depreciation_amount
 			row.db_update()
 
-	frappe.db.set_value("Asset", asset_name, "depr_entry_posting_status", "Successful")
+	asset.db_set("depr_entry_posting_status", "Successful")
 
 	asset.set_status()
 
diff --git a/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.py b/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.py
index 7615fbc..6f02662 100644
--- a/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.py
+++ b/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.py
@@ -134,7 +134,7 @@
 	):
 		asset_doc.validate_asset_finance_books(row)
 
-		value_after_depreciation = asset_doc._get_value_after_depreciation_for_making_schedule(row)
+		value_after_depreciation = _get_value_after_depreciation_for_making_schedule(asset_doc, row)
 		row.value_after_depreciation = value_after_depreciation
 
 		if update_asset_finance_book_row:
@@ -325,6 +325,17 @@
 			)
 
 
+def _get_value_after_depreciation_for_making_schedule(asset_doc, fb_row):
+	if asset_doc.docstatus == 1 and fb_row.value_after_depreciation:
+		value_after_depreciation = flt(fb_row.value_after_depreciation)
+	else:
+		value_after_depreciation = flt(asset_doc.gross_purchase_amount) - flt(
+			asset_doc.opening_accumulated_depreciation
+		)
+
+	return value_after_depreciation
+
+
 def make_draft_asset_depr_schedules_if_not_present(asset_doc):
 	for row in asset_doc.get("finance_books"):
 		draft_asset_depr_schedule_name = get_asset_depr_schedule_name(
diff --git a/erpnext/assets/doctype/asset_repair/asset_repair.py b/erpnext/assets/doctype/asset_repair/asset_repair.py
index 9a05a74..a7172a7 100644
--- a/erpnext/assets/doctype/asset_repair/asset_repair.py
+++ b/erpnext/assets/doctype/asset_repair/asset_repair.py
@@ -91,6 +91,9 @@
 		make_new_active_asset_depr_schedules_and_cancel_current_ones(self.asset_doc, notes)
 		self.asset_doc.save()
 
+	def after_delete(self):
+		frappe.get_doc("Asset", self.asset).set_status()
+
 	def check_repair_status(self):
 		if self.repair_status == "Pending":
 			frappe.throw(_("Please update Repair Status."))
diff --git a/erpnext/assets/report/fixed_asset_register/fixed_asset_register.py b/erpnext/assets/report/fixed_asset_register/fixed_asset_register.py
index cead72e..59d43b1 100644
--- a/erpnext/assets/report/fixed_asset_register/fixed_asset_register.py
+++ b/erpnext/assets/report/fixed_asset_register/fixed_asset_register.py
@@ -5,7 +5,7 @@
 import frappe
 from frappe import _
 from frappe.query_builder.functions import Sum
-from frappe.utils import cstr, formatdate, getdate
+from frappe.utils import cstr, flt, formatdate, getdate
 
 from erpnext.accounts.report.financial_statements import (
 	get_fiscal_year_data,
@@ -102,13 +102,9 @@
 		]
 		assets_record = frappe.db.get_all("Asset", filters=conditions, fields=fields)
 
-	finance_book_filter = ("is", "not set")
-	if filters.finance_book:
-		finance_book_filter = ("=", filters.finance_book)
-
 	assets_linked_to_fb = frappe.db.get_all(
 		doctype="Asset Finance Book",
-		filters={"finance_book": finance_book_filter},
+		filters={"finance_book": filters.finance_book or ("is", "not set")},
 		pluck="parent",
 	)
 
@@ -155,6 +151,7 @@
 		filters.filter_based_on,
 		"Monthly",
 		company=filters.company,
+		ignore_fiscal_year=True,
 	)
 
 	for d in period_list:
@@ -194,7 +191,7 @@
 	else:
 		depr_amount = get_manual_depreciation_amount_of_asset(asset, filters)
 
-	return depr_amount
+	return flt(depr_amount, 2)
 
 
 def get_finance_book_value_map(filters):
diff --git a/erpnext/buying/doctype/buying_settings/buying_settings.json b/erpnext/buying/doctype/buying_settings/buying_settings.json
index 34417f7..652dcf0 100644
--- a/erpnext/buying/doctype/buying_settings/buying_settings.json
+++ b/erpnext/buying/doctype/buying_settings/buying_settings.json
@@ -21,6 +21,7 @@
   "allow_multiple_items",
   "bill_for_rejected_quantity_in_purchase_invoice",
   "disable_last_purchase_rate",
+  "show_pay_button",
   "subcontract",
   "backflush_raw_materials_of_subcontract_based_on",
   "column_break_11",
@@ -140,6 +141,12 @@
    "fieldname": "disable_last_purchase_rate",
    "fieldtype": "Check",
    "label": "Disable Last Purchase Rate"
+  },
+  {
+   "default": "1",
+   "fieldname": "show_pay_button",
+   "fieldtype": "Check",
+   "label": "Show Pay Button in Purchase Order Portal"
   }
  ],
  "icon": "fa fa-cog",
@@ -147,7 +154,7 @@
  "index_web_pages_for_search": 1,
  "issingle": 1,
  "links": [],
- "modified": "2023-01-09 17:08:28.828173",
+ "modified": "2023-02-15 14:42:10.200679",
  "modified_by": "Administrator",
  "module": "Buying",
  "name": "Buying Settings",
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 a9f5afb..2f0b786 100644
--- a/erpnext/buying/doctype/request_for_quotation/request_for_quotation.js
+++ b/erpnext/buying/doctype/request_for_quotation/request_for_quotation.js
@@ -124,12 +124,11 @@
 								frappe.urllib.get_full_url(
 									"/api/method/erpnext.buying.doctype.request_for_quotation.request_for_quotation.get_pdf?" +
 									new URLSearchParams({
-										doctype: frm.doc.doctype,
 										name: frm.doc.name,
 										supplier: data.supplier,
 										print_format: data.print_format || "Standard",
 										language: data.language || frappe.boot.lang,
-										letter_head: data.letter_head || frm.doc.letter_head || "",
+										letterhead: data.letter_head || frm.doc.letter_head || "",
 									}).toString()
 								)
 							);
diff --git a/erpnext/buying/doctype/request_for_quotation/request_for_quotation.py b/erpnext/buying/doctype/request_for_quotation/request_for_quotation.py
index 8e9ded9..7927beb 100644
--- a/erpnext/buying/doctype/request_for_quotation/request_for_quotation.py
+++ b/erpnext/buying/doctype/request_for_quotation/request_for_quotation.py
@@ -3,6 +3,7 @@
 
 
 import json
+from typing import Optional
 
 import frappe
 from frappe import _
@@ -388,24 +389,26 @@
 
 
 @frappe.whitelist()
-def get_pdf(doctype, name, supplier, print_format=None, language=None, letter_head=None):
-	# permissions get checked in `download_pdf`
-	if doc := get_rfq_doc(doctype, name, supplier):
-		download_pdf(
-			doctype,
-			name,
-			print_format,
-			doc=doc,
-			language=language,
-			letter_head=letter_head or None,
-		)
-
-
-def get_rfq_doc(doctype, name, supplier):
+def get_pdf(
+	name: str,
+	supplier: str,
+	print_format: Optional[str] = None,
+	language: Optional[str] = None,
+	letterhead: Optional[str] = None,
+):
+	doc = frappe.get_doc("Request for Quotation", name)
 	if supplier:
-		doc = frappe.get_doc(doctype, name)
 		doc.update_supplier_part_no(supplier)
-		return doc
+
+	# permissions get checked in `download_pdf`
+	download_pdf(
+		doc.doctype,
+		doc.name,
+		print_format,
+		doc=doc,
+		language=language,
+		letterhead=letterhead or None,
+	)
 
 
 @frappe.whitelist()
diff --git a/erpnext/buying/doctype/request_for_quotation/test_request_for_quotation.py b/erpnext/buying/doctype/request_for_quotation/test_request_for_quotation.py
index 064b806..d250e6f 100644
--- a/erpnext/buying/doctype/request_for_quotation/test_request_for_quotation.py
+++ b/erpnext/buying/doctype/request_for_quotation/test_request_for_quotation.py
@@ -8,6 +8,7 @@
 
 from erpnext.buying.doctype.request_for_quotation.request_for_quotation import (
 	create_supplier_quotation,
+	get_pdf,
 	make_supplier_quotation_from_rfq,
 )
 from erpnext.crm.doctype.opportunity.opportunity import make_request_for_quotation as make_rfq
@@ -124,6 +125,11 @@
 		rfq.status = "Draft"
 		rfq.submit()
 
+	def test_get_pdf(self):
+		rfq = make_request_for_quotation()
+		get_pdf(rfq.name, rfq.get("suppliers")[0].supplier)
+		self.assertEqual(frappe.local.response.type, "pdf")
+
 
 def make_request_for_quotation(**args):
 	"""
diff --git a/erpnext/buying/doctype/supplier/supplier.json b/erpnext/buying/doctype/supplier/supplier.json
index 66eafe9..1bf7f58 100644
--- a/erpnext/buying/doctype/supplier/supplier.json
+++ b/erpnext/buying/doctype/supplier/supplier.json
@@ -23,7 +23,6 @@
   "default_bank_account",
   "column_break_10",
   "default_price_list",
-  "payment_terms",
   "internal_supplier_section",
   "is_internal_supplier",
   "represents_company",
@@ -53,6 +52,7 @@
   "supplier_primary_address",
   "primary_address",
   "accounting_tab",
+  "payment_terms",
   "accounts",
   "settings_tab",
   "allow_purchase_invoice_creation_without_purchase_order",
@@ -457,11 +457,10 @@
    "link_fieldname": "party"
   }
  ],
- "modified": "2022-11-09 18:02:59.075203",
+ "modified": "2023-02-18 11:05:50.592270",
  "modified_by": "Administrator",
  "module": "Buying",
  "name": "Supplier",
- "name_case": "Title Case",
  "naming_rule": "By \"Naming Series\" field",
  "owner": "Administrator",
  "permissions": [
diff --git a/erpnext/controllers/accounts_controller.py b/erpnext/controllers/accounts_controller.py
index 6fa44c9..3705fcf 100644
--- a/erpnext/controllers/accounts_controller.py
+++ b/erpnext/controllers/accounts_controller.py
@@ -204,6 +204,12 @@
 		validate_einvoice_fields(self)
 
 	def on_trash(self):
+		# delete references in 'Repost Payment Ledger'
+		rpi = frappe.qb.DocType("Repost Payment Ledger Items")
+		frappe.qb.from_(rpi).delete().where(
+			(rpi.voucher_type == self.doctype) & (rpi.voucher_no == self.name)
+		).run()
+
 		# delete sl and gl entries on deletion of transaction
 		if frappe.db.get_single_value("Accounts Settings", "delete_linked_ledger_entries"):
 			ple = frappe.qb.DocType("Payment Ledger Entry")
diff --git a/erpnext/controllers/sales_and_purchase_return.py b/erpnext/controllers/sales_and_purchase_return.py
index 9fcb769..fc6793a 100644
--- a/erpnext/controllers/sales_and_purchase_return.py
+++ b/erpnext/controllers/sales_and_purchase_return.py
@@ -252,6 +252,7 @@
 			child.parent = par.name and par.docstatus = 1
 			and par.is_return = 1 and par.return_against = %s
 		group by item_code
+		for update
 	""".format(
 			column, doc.doctype, doc.doctype
 		),
diff --git a/erpnext/controllers/subcontracting_controller.py b/erpnext/controllers/subcontracting_controller.py
index a9561fe..cc80f6c 100644
--- a/erpnext/controllers/subcontracting_controller.py
+++ b/erpnext/controllers/subcontracting_controller.py
@@ -409,7 +409,14 @@
 		if self.available_materials.get(key) and self.available_materials[key]["batch_no"]:
 			new_rm_obj = None
 			for batch_no, batch_qty in self.available_materials[key]["batch_no"].items():
-				if batch_qty >= qty:
+				if batch_qty >= qty or (
+					rm_obj.consumed_qty == 0
+					and self.backflush_based_on == "BOM"
+					and len(self.available_materials[key]["batch_no"]) == 1
+				):
+					if rm_obj.consumed_qty == 0:
+						self.__set_consumed_qty(rm_obj, qty)
+
 					self.__set_batch_no_as_per_qty(item_row, rm_obj, batch_no, qty)
 					self.available_materials[key]["batch_no"][batch_no] -= qty
 					return
diff --git a/erpnext/crm/doctype/lead_source/lead_source.json b/erpnext/crm/doctype/lead_source/lead_source.json
index 723c6d9..c3cedcc 100644
--- a/erpnext/crm/doctype/lead_source/lead_source.json
+++ b/erpnext/crm/doctype/lead_source/lead_source.json
@@ -26,10 +26,11 @@
   }
  ],
  "links": [],
- "modified": "2021-02-08 12:51:48.971517",
+ "modified": "2023-02-10 00:51:44.973957",
  "modified_by": "Administrator",
  "module": "CRM",
  "name": "Lead Source",
+ "naming_rule": "By fieldname",
  "owner": "Administrator",
  "permissions": [
   {
@@ -58,5 +59,7 @@
  ],
  "quick_entry": 1,
  "sort_field": "modified",
- "sort_order": "DESC"
+ "sort_order": "DESC",
+ "states": [],
+ "translated_doctype": 1
 }
\ No newline at end of file
diff --git a/erpnext/crm/doctype/sales_stage/sales_stage.json b/erpnext/crm/doctype/sales_stage/sales_stage.json
index 77aa559..caf8ff5 100644
--- a/erpnext/crm/doctype/sales_stage/sales_stage.json
+++ b/erpnext/crm/doctype/sales_stage/sales_stage.json
@@ -18,10 +18,11 @@
   }
  ],
  "links": [],
- "modified": "2020-05-20 12:22:01.866472",
+ "modified": "2023-02-10 01:40:23.713390",
  "modified_by": "Administrator",
  "module": "CRM",
  "name": "Sales Stage",
+ "naming_rule": "By fieldname",
  "owner": "Administrator",
  "permissions": [
   {
@@ -40,5 +41,7 @@
  "quick_entry": 1,
  "sort_field": "modified",
  "sort_order": "DESC",
- "track_changes": 1
+ "states": [],
+ "track_changes": 1,
+ "translated_doctype": 1
 }
\ No newline at end of file
diff --git a/erpnext/erpnext_integrations/doctype/plaid_settings/plaid_connector.py b/erpnext/erpnext_integrations/doctype/plaid_settings/plaid_connector.py
index 38d6993..f44fad3 100644
--- a/erpnext/erpnext_integrations/doctype/plaid_settings/plaid_connector.py
+++ b/erpnext/erpnext_integrations/doctype/plaid_settings/plaid_connector.py
@@ -12,7 +12,7 @@
 	def __init__(self, access_token=None):
 		self.access_token = access_token
 		self.settings = frappe.get_single("Plaid Settings")
-		self.products = ["auth", "transactions"]
+		self.products = ["transactions"]
 		self.client_name = frappe.local.site
 		self.client = plaid.Client(
 			client_id=self.settings.plaid_client_id,
diff --git a/erpnext/erpnext_integrations/doctype/plaid_settings/plaid_settings.js b/erpnext/erpnext_integrations/doctype/plaid_settings/plaid_settings.js
index 3740d04..3ba6bb9 100644
--- a/erpnext/erpnext_integrations/doctype/plaid_settings/plaid_settings.js
+++ b/erpnext/erpnext_integrations/doctype/plaid_settings/plaid_settings.js
@@ -47,7 +47,7 @@
 	}
 
 	async init_config() {
-		this.product = ["auth", "transactions"];
+		this.product = ["transactions"];
 		this.plaid_env = this.frm.doc.plaid_env;
 		this.client_name = frappe.boot.sitename;
 		this.token = await this.get_link_token();
diff --git a/erpnext/erpnext_integrations/doctype/plaid_settings/plaid_settings.py b/erpnext/erpnext_integrations/doctype/plaid_settings/plaid_settings.py
index 62ea85f..f3aa6a3 100644
--- a/erpnext/erpnext_integrations/doctype/plaid_settings/plaid_settings.py
+++ b/erpnext/erpnext_integrations/doctype/plaid_settings/plaid_settings.py
@@ -70,7 +70,8 @@
 	except TypeError:
 		pass
 
-	bank = json.loads(bank)
+	if isinstance(bank, str):
+		bank = json.loads(bank)
 	result = []
 
 	default_gl_account = get_default_bank_cash_account(company, "Bank")
@@ -177,16 +178,15 @@
 		)
 
 		result = []
-		for transaction in reversed(transactions):
-			result += new_bank_transaction(transaction)
+		if transactions:
+			for transaction in reversed(transactions):
+				result += new_bank_transaction(transaction)
 
 		if result:
 			last_transaction_date = frappe.db.get_value("Bank Transaction", result.pop(), "date")
 
 			frappe.logger().info(
-				"Plaid added {} new Bank Transactions from '{}' between {} and {}".format(
-					len(result), bank_account, start_date, end_date
-				)
+				f"Plaid added {len(result)} new Bank Transactions from '{bank_account}' between {start_date} and {end_date}"
 			)
 
 			frappe.db.set_value(
@@ -230,19 +230,20 @@
 
 	bank_account = frappe.db.get_value("Bank Account", dict(integration_id=transaction["account_id"]))
 
-	if float(transaction["amount"]) >= 0:
-		debit = 0
-		credit = float(transaction["amount"])
+	amount = float(transaction["amount"])
+	if amount >= 0.0:
+		deposit = 0.0
+		withdrawal = amount
 	else:
-		debit = abs(float(transaction["amount"]))
-		credit = 0
+		deposit = abs(amount)
+		withdrawal = 0.0
 
 	status = "Pending" if transaction["pending"] == "True" else "Settled"
 
 	tags = []
 	try:
 		tags += transaction["category"]
-		tags += ["Plaid Cat. {}".format(transaction["category_id"])]
+		tags += [f'Plaid Cat. {transaction["category_id"]}']
 	except KeyError:
 		pass
 
@@ -254,11 +255,18 @@
 					"date": getdate(transaction["date"]),
 					"status": status,
 					"bank_account": bank_account,
-					"deposit": debit,
-					"withdrawal": credit,
+					"deposit": deposit,
+					"withdrawal": withdrawal,
 					"currency": transaction["iso_currency_code"],
 					"transaction_id": transaction["transaction_id"],
-					"reference_number": transaction["payment_meta"]["reference_number"],
+					"transaction_type": (
+						transaction["transaction_code"] or transaction["payment_meta"]["payment_method"]
+					),
+					"reference_number": (
+						transaction["check_number"]
+						or transaction["payment_meta"]["reference_number"]
+						or transaction["name"]
+					),
 					"description": transaction["name"],
 				}
 			)
@@ -271,7 +279,7 @@
 			result.append(new_transaction.name)
 
 		except Exception:
-			frappe.throw(title=_("Bank transaction creation error"))
+			frappe.throw(_("Bank transaction creation error"))
 
 	return result
 
@@ -300,3 +308,26 @@
 def get_link_token_for_update(access_token):
 	plaid = PlaidConnector(access_token)
 	return plaid.get_link_token(update_mode=True)
+
+
+def get_company(bank_account_name):
+	from frappe.defaults import get_user_default
+
+	company_names = frappe.db.get_all("Company", pluck="name")
+	if len(company_names) == 1:
+		return company_names[0]
+	if frappe.db.exists("Bank Account", bank_account_name):
+		return frappe.db.get_value("Bank Account", bank_account_name, "company")
+	company_default = get_user_default("Company")
+	if company_default:
+		return company_default
+	frappe.throw(_("Could not detect the Company for updating Bank Accounts"))
+
+
+@frappe.whitelist()
+def update_bank_account_ids(response):
+	data = json.loads(response)
+	institution_name = data["institution"]["name"]
+	bank = frappe.get_doc("Bank", institution_name).as_dict()
+	bank_account_name = f"{data['account']['name']} - {institution_name}"
+	return add_bank_accounts(response, bank, get_company(bank_account_name))
diff --git a/erpnext/erpnext_integrations/doctype/plaid_settings/test_plaid_settings.py b/erpnext/erpnext_integrations/doctype/plaid_settings/test_plaid_settings.py
index e8dc3e2..6d34a20 100644
--- a/erpnext/erpnext_integrations/doctype/plaid_settings/test_plaid_settings.py
+++ b/erpnext/erpnext_integrations/doctype/plaid_settings/test_plaid_settings.py
@@ -125,6 +125,8 @@
 			"unofficial_currency_code": None,
 			"name": "INTRST PYMNT",
 			"transaction_type": "place",
+			"transaction_code": "direct debit",
+			"check_number": "3456789",
 			"amount": -4.22,
 			"location": {
 				"city": None,
diff --git a/erpnext/hooks.py b/erpnext/hooks.py
index fd19d25..fba886c 100644
--- a/erpnext/hooks.py
+++ b/erpnext/hooks.py
@@ -311,15 +311,10 @@
 		"on_submit": [
 			"erpnext.regional.create_transaction_log",
 			"erpnext.regional.italy.utils.sales_invoice_on_submit",
-			"erpnext.regional.saudi_arabia.utils.create_qr_code",
 		],
-		"on_cancel": [
-			"erpnext.regional.italy.utils.sales_invoice_on_cancel",
-			"erpnext.regional.saudi_arabia.utils.delete_qr_code_file",
-		],
+		"on_cancel": ["erpnext.regional.italy.utils.sales_invoice_on_cancel"],
 		"on_trash": "erpnext.regional.check_deletion_permission",
 	},
-	"POS Invoice": {"on_submit": ["erpnext.regional.saudi_arabia.utils.create_qr_code"]},
 	"Purchase Invoice": {
 		"validate": [
 			"erpnext.regional.united_arab_emirates.utils.update_grand_total_for_rcm",
@@ -347,7 +342,6 @@
 	"Email Unsubscribe": {
 		"after_insert": "erpnext.crm.doctype.email_campaign.email_campaign.unsubscribe_recipient"
 	},
-	"Company": {"on_trash": ["erpnext.regional.saudi_arabia.utils.delete_vat_settings_for_company"]},
 	"Integration Request": {
 		"validate": "erpnext.accounts.doctype.payment_request.payment_request.validate_payment"
 	},
diff --git a/erpnext/manufacturing/doctype/bom/bom.json b/erpnext/manufacturing/doctype/bom/bom.json
index c2b331f..db699b9 100644
--- a/erpnext/manufacturing/doctype/bom/bom.json
+++ b/erpnext/manufacturing/doctype/bom/bom.json
@@ -289,7 +289,7 @@
   {
    "fieldname": "scrap_items",
    "fieldtype": "Table",
-   "label": "Items",
+   "label": "Scrap Items",
    "options": "BOM Scrap Item"
   },
   {
@@ -605,7 +605,7 @@
  "image_field": "image",
  "is_submittable": 1,
  "links": [],
- "modified": "2023-01-10 07:47:08.652616",
+ "modified": "2023-02-13 17:31:37.504565",
  "modified_by": "Administrator",
  "module": "Manufacturing",
  "name": "BOM",
diff --git a/erpnext/manufacturing/report/bom_stock_report/bom_stock_report.js b/erpnext/manufacturing/report/bom_stock_report/bom_stock_report.js
index 7beecac..e7f67ca 100644
--- a/erpnext/manufacturing/report/bom_stock_report/bom_stock_report.js
+++ b/erpnext/manufacturing/report/bom_stock_report/bom_stock_report.js
@@ -25,8 +25,9 @@
 	],
 	"formatter": function(value, row, column, data, default_formatter) {
 		value = default_formatter(value, row, column, data);
+
 		if (column.id == "item") {
-			if (data["enough_parts_to_build"] > 0) {
+			if (data["in_stock_qty"] >= data["required_qty"]) {
 				value = `<a style='color:green' href="/app/item/${data['item']}" data-doctype="Item">${data['item']}</a>`;
 			} else {
 				value = `<a style='color:red' href="/app/item/${data['item']}" data-doctype="Item">${data['item']}</a>`;
diff --git a/erpnext/patches.txt b/erpnext/patches.txt
index 211f074..2abd65b 100644
--- a/erpnext/patches.txt
+++ b/erpnext/patches.txt
@@ -250,18 +250,14 @@
 erpnext.patches.v13_0.update_category_in_ltds_certificate
 erpnext.patches.v13_0.fetch_thumbnail_in_website_items
 erpnext.patches.v13_0.update_maintenance_schedule_field_in_visit
-erpnext.patches.v13_0.create_ksa_vat_custom_fields # 07-01-2022
 erpnext.patches.v14_0.migrate_crm_settings
-erpnext.patches.v13_0.rename_ksa_qr_field
 erpnext.patches.v13_0.wipe_serial_no_field_for_0_qty
-erpnext.patches.v13_0.disable_ksa_print_format_for_others # 16-12-2021
 erpnext.patches.v13_0.agriculture_deprecation_warning
 erpnext.patches.v13_0.hospitality_deprecation_warning
 erpnext.patches.v13_0.update_asset_quantity_field
 erpnext.patches.v13_0.delete_bank_reconciliation_detail
 erpnext.patches.v13_0.enable_provisional_accounting
 erpnext.patches.v13_0.non_profit_deprecation_warning
-erpnext.patches.v13_0.enable_ksa_vat_docs #1
 erpnext.patches.v13_0.show_india_localisation_deprecation_warning
 erpnext.patches.v13_0.show_hr_payroll_deprecation_warning
 erpnext.patches.v13_0.reset_corrupt_defaults
@@ -269,6 +265,8 @@
 erpnext.patches.v15_0.delete_taxjar_doctypes
 erpnext.patches.v15_0.create_asset_depreciation_schedules_from_assets
 erpnext.patches.v14_0.update_reference_due_date_in_journal_entry
+erpnext.patches.v15_0.saudi_depreciation_warning
+erpnext.patches.v15_0.delete_saudi_doctypes
 
 [post_model_sync]
 execute:frappe.delete_doc_if_exists('Workspace', 'ERPNext Integrations Settings')
@@ -306,7 +304,6 @@
 execute:frappe.delete_doc("DocType", "Naming Series")
 erpnext.patches.v13_0.job_card_status_on_hold
 erpnext.patches.v14_0.copy_is_subcontracted_value_to_is_old_subcontracting_flow
-erpnext.patches.v14_0.migrate_gl_to_payment_ledger
 erpnext.patches.v14_0.crm_ux_cleanup
 erpnext.patches.v14_0.migrate_existing_lead_notes_as_per_the_new_format
 erpnext.patches.v14_0.remove_india_localisation # 14-07-2022
@@ -315,7 +312,6 @@
 erpnext.patches.v14_0.fix_crm_no_of_employees
 erpnext.patches.v14_0.create_accounting_dimensions_in_subcontracting_doctypes
 erpnext.patches.v14_0.fix_subcontracting_receipt_gl_entries
-erpnext.patches.v14_0.migrate_remarks_from_gl_to_payment_ledger
 erpnext.patches.v13_0.update_schedule_type_in_loans
 erpnext.patches.v13_0.drop_unused_sle_index_parts
 erpnext.patches.v14_0.create_accounting_dimensions_for_asset_capitalization
@@ -327,3 +323,6 @@
 erpnext.patches.v14_0.change_autoname_for_tax_withheld_vouchers
 erpnext.patches.v14_0.set_pick_list_status
 erpnext.patches.v15_0.update_asset_value_for_manual_depr_entries
+# below 2 migration patches should always run last
+erpnext.patches.v14_0.migrate_gl_to_payment_ledger
+erpnext.patches.v14_0.migrate_remarks_from_gl_to_payment_ledger
diff --git a/erpnext/patches/v11_0/update_sales_partner_type.py b/erpnext/patches/v11_0/update_sales_partner_type.py
index 2d37fd6..72fd424 100644
--- a/erpnext/patches/v11_0/update_sales_partner_type.py
+++ b/erpnext/patches/v11_0/update_sales_partner_type.py
@@ -1,16 +1,17 @@
 import frappe
-from frappe import _
 
 
 def execute():
-	from erpnext.setup.setup_wizard.operations.install_fixtures import default_sales_partner_type
+	from erpnext.setup.setup_wizard.operations.install_fixtures import read_lines
 
 	frappe.reload_doc("selling", "doctype", "sales_partner_type")
 
 	frappe.local.lang = frappe.db.get_default("lang") or "en"
 
+	default_sales_partner_type = read_lines("sales_partner_type.txt")
+
 	for s in default_sales_partner_type:
-		insert_sales_partner_type(_(s))
+		insert_sales_partner_type(s)
 
 	# get partner type in existing forms (customized)
 	# and create a document if not created
diff --git a/erpnext/patches/v13_0/create_ksa_vat_custom_fields.py b/erpnext/patches/v13_0/create_ksa_vat_custom_fields.py
deleted file mode 100644
index 093463a..0000000
--- a/erpnext/patches/v13_0/create_ksa_vat_custom_fields.py
+++ /dev/null
@@ -1,11 +0,0 @@
-import frappe
-
-from erpnext.regional.saudi_arabia.setup import make_custom_fields
-
-
-def execute():
-	company = frappe.get_all("Company", filters={"country": "Saudi Arabia"})
-	if not company:
-		return
-
-	make_custom_fields()
diff --git a/erpnext/patches/v13_0/delete_old_purchase_reports.py b/erpnext/patches/v13_0/delete_old_purchase_reports.py
index 987f53f..60621fb 100644
--- a/erpnext/patches/v13_0/delete_old_purchase_reports.py
+++ b/erpnext/patches/v13_0/delete_old_purchase_reports.py
@@ -17,10 +17,11 @@
 
 	for report in reports_to_delete:
 		if frappe.db.exists("Report", report):
+			delete_links_from_desktop_icons(report)
 			delete_auto_email_reports(report)
 			check_and_delete_linked_reports(report)
 
-			frappe.delete_doc("Report", report)
+			frappe.delete_doc("Report", report, force=True)
 
 
 def delete_auto_email_reports(report):
@@ -28,3 +29,10 @@
 	auto_email_reports = frappe.db.get_values("Auto Email Report", {"report": report}, ["name"])
 	for auto_email_report in auto_email_reports:
 		frappe.delete_doc("Auto Email Report", auto_email_report[0])
+
+
+def delete_links_from_desktop_icons(report):
+	"""Check for one or multiple Desktop Icons and delete"""
+	desktop_icons = frappe.db.get_values("Desktop Icon", {"_report": report}, ["name"])
+	for desktop_icon in desktop_icons:
+		frappe.delete_doc("Desktop Icon", desktop_icon[0], force=True)
diff --git a/erpnext/patches/v13_0/disable_ksa_print_format_for_others.py b/erpnext/patches/v13_0/disable_ksa_print_format_for_others.py
deleted file mode 100644
index 84b6c37..0000000
--- a/erpnext/patches/v13_0/disable_ksa_print_format_for_others.py
+++ /dev/null
@@ -1,19 +0,0 @@
-# Copyright (c) 2020, Wahni Green Technologies and Contributors
-# License: GNU General Public License v3. See license.txt
-
-import frappe
-
-from erpnext.regional.saudi_arabia.setup import add_print_formats
-
-
-def execute():
-	company = frappe.get_all("Company", filters={"country": "Saudi Arabia"})
-	if company:
-		add_print_formats()
-		return
-
-	if frappe.db.exists("DocType", "Print Format"):
-		frappe.reload_doc("regional", "print_format", "ksa_vat_invoice", force=True)
-		frappe.reload_doc("regional", "print_format", "ksa_pos_invoice", force=True)
-		for d in ("KSA VAT Invoice", "KSA POS Invoice"):
-			frappe.db.set_value("Print Format", d, "disabled", 1)
diff --git a/erpnext/patches/v13_0/enable_ksa_vat_docs.py b/erpnext/patches/v13_0/enable_ksa_vat_docs.py
deleted file mode 100644
index 4adf4d7..0000000
--- a/erpnext/patches/v13_0/enable_ksa_vat_docs.py
+++ /dev/null
@@ -1,12 +0,0 @@
-import frappe
-
-from erpnext.regional.saudi_arabia.setup import add_permissions, add_print_formats
-
-
-def execute():
-	company = frappe.get_all("Company", filters={"country": "Saudi Arabia"})
-	if not company:
-		return
-
-	add_print_formats()
-	add_permissions()
diff --git a/erpnext/patches/v13_0/rename_ksa_qr_field.py b/erpnext/patches/v13_0/rename_ksa_qr_field.py
deleted file mode 100644
index e4b9141..0000000
--- a/erpnext/patches/v13_0/rename_ksa_qr_field.py
+++ /dev/null
@@ -1,36 +0,0 @@
-# Copyright (c) 2020, Wahni Green Technologies and Contributors
-# 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
-
-
-def execute():
-	company = frappe.get_all("Company", filters={"country": "Saudi Arabia"})
-	if not company:
-		return
-
-	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/patches/v15_0/delete_saudi_doctypes.py b/erpnext/patches/v15_0/delete_saudi_doctypes.py
new file mode 100644
index 0000000..371e335
--- /dev/null
+++ b/erpnext/patches/v15_0/delete_saudi_doctypes.py
@@ -0,0 +1,25 @@
+import click
+import frappe
+
+
+def execute():
+	if "ksa" in frappe.get_installed_apps():
+		return
+
+	doctypes = ["KSA VAT Setting", "KSA VAT Purchase Account", "KSA VAT Sales Account"]
+	for doctype in doctypes:
+		frappe.delete_doc("DocType", doctype, ignore_missing=True)
+
+	print_formats = ["KSA POS Invoice", "KSA VAT Invoice"]
+	for print_format in print_formats:
+		frappe.delete_doc("Print Format", print_format, ignore_missing=True, force=True)
+
+	reports = ["KSA VAT"]
+	for report in reports:
+		frappe.delete_doc("Report", report, ignore_missing=True, force=True)
+
+	click.secho(
+		"Region Saudi Arabia(KSA) is moved to a separate app"
+		"Please install the app to continue using the module: https://github.com/8848digital/KSA",
+		fg="yellow",
+	)
diff --git a/erpnext/patches/v15_0/saudi_depreciation_warning.py b/erpnext/patches/v15_0/saudi_depreciation_warning.py
new file mode 100644
index 0000000..6af8efe
--- /dev/null
+++ b/erpnext/patches/v15_0/saudi_depreciation_warning.py
@@ -0,0 +1,12 @@
+import click
+import frappe
+
+
+def execute():
+	if "ksa" in frappe.get_installed_apps():
+		return
+	click.secho(
+		"Region Saudi Arabia(KSA) is moved to a separate app\n"
+		"Please install the app to continue using the KSA Features: https://github.com/8848digital/KSA",
+		fg="yellow",
+	)
diff --git a/erpnext/projects/doctype/project/project.json b/erpnext/projects/doctype/project/project.json
index 37d98ad..ba7aa85 100644
--- a/erpnext/projects/doctype/project/project.json
+++ b/erpnext/projects/doctype/project/project.json
@@ -408,7 +408,7 @@
    "depends_on": "eval:(doc.frequency == \"Daily\" && doc.collect_progress == true)",
    "fieldname": "daily_time_to_send",
    "fieldtype": "Time",
-   "label": "Time to send"
+   "label": "Daily Time to send"
   },
   {
    "depends_on": "eval:(doc.frequency == \"Weekly\" && doc.collect_progress == true)",
@@ -421,7 +421,7 @@
    "depends_on": "eval:(doc.frequency == \"Weekly\" && doc.collect_progress == true)",
    "fieldname": "weekly_time_to_send",
    "fieldtype": "Time",
-   "label": "Time to send"
+   "label": "Weekly Time to send"
   },
   {
    "fieldname": "column_break_45",
@@ -451,7 +451,7 @@
  "index_web_pages_for_search": 1,
  "links": [],
  "max_attachments": 4,
- "modified": "2022-06-23 16:45:06.108499",
+ "modified": "2023-02-14 04:54:25.819620",
  "modified_by": "Administrator",
  "module": "Projects",
  "name": "Project",
@@ -497,4 +497,4 @@
  "timeline_field": "customer",
  "title_field": "project_name",
  "track_seen": 1
-}
+}
\ No newline at end of file
diff --git a/erpnext/projects/doctype/timesheet/timesheet.json b/erpnext/projects/doctype/timesheet/timesheet.json
index 0cce129..4683006 100644
--- a/erpnext/projects/doctype/timesheet/timesheet.json
+++ b/erpnext/projects/doctype/timesheet/timesheet.json
@@ -282,21 +282,21 @@
   {
    "fieldname": "base_total_costing_amount",
    "fieldtype": "Currency",
-   "label": "Total Costing Amount",
+   "label": "Base Total Costing Amount",
    "print_hide": 1,
    "read_only": 1
   },
   {
    "fieldname": "base_total_billable_amount",
    "fieldtype": "Currency",
-   "label": "Total Billable Amount",
+   "label": "Base Total Billable Amount",
    "print_hide": 1,
    "read_only": 1
   },
   {
    "fieldname": "base_total_billed_amount",
    "fieldtype": "Currency",
-   "label": "Total Billed Amount",
+   "label": "Base Total Billed Amount",
    "print_hide": 1,
    "read_only": 1
   },
@@ -311,10 +311,11 @@
  "idx": 1,
  "is_submittable": 1,
  "links": [],
- "modified": "2022-06-15 22:08:53.930200",
+ "modified": "2023-02-14 04:55:41.735991",
  "modified_by": "Administrator",
  "module": "Projects",
  "name": "Timesheet",
+ "naming_rule": "By \"Naming Series\" field",
  "owner": "Administrator",
  "permissions": [
   {
@@ -388,5 +389,6 @@
  ],
  "sort_field": "modified",
  "sort_order": "ASC",
+ "states": [],
  "title_field": "title"
 }
\ No newline at end of file
diff --git a/erpnext/public/js/bank_reconciliation_tool/data_table_manager.js b/erpnext/public/js/bank_reconciliation_tool/data_table_manager.js
index f7c19a1..0cda938 100644
--- a/erpnext/public/js/bank_reconciliation_tool/data_table_manager.js
+++ b/erpnext/public/js/bank_reconciliation_tool/data_table_manager.js
@@ -182,6 +182,9 @@
 			);
 		} else {
 			this.transactions.splice(transaction_index, 1);
+			for (const [k, v] of Object.entries(this.transaction_dt_map)) {
+				if (v > transaction_index) this.transaction_dt_map[k] = v - 1;
+			}
 		}
 		this.datatable.refresh(this.transactions, this.columns);
 
diff --git a/erpnext/public/js/bank_reconciliation_tool/dialog_manager.js b/erpnext/public/js/bank_reconciliation_tool/dialog_manager.js
index 911343d..321b812 100644
--- a/erpnext/public/js/bank_reconciliation_tool/dialog_manager.js
+++ b/erpnext/public/js/bank_reconciliation_tool/dialog_manager.js
@@ -20,7 +20,7 @@
 				doctype: "Bank Transaction",
 				filters: { name: this.bank_transaction_name },
 				fieldname: [
-					"date as reference_date",
+					"date",
 					"deposit",
 					"withdrawal",
 					"currency",
@@ -33,6 +33,7 @@
 					"party",
 					"unallocated_amount",
 					"allocated_amount",
+					"transaction_type",
 				],
 			},
 			callback: (r) => {
@@ -41,11 +42,23 @@
 					r.message.payment_entry = 1;
 					r.message.journal_entry = 1;
 					this.dialog.set_values(r.message);
+					this.copy_data_to_voucher();
 					this.dialog.show();
 				}
 			},
 		});
 	}
+
+	copy_data_to_voucher() {
+		let copied = {
+			reference_number: this.bank_transaction.reference_number || this.bank_transaction.description,
+			posting_date: this.bank_transaction.date,
+			reference_date: this.bank_transaction.date,
+			mode_of_payment: this.bank_transaction.transaction_type,
+		};
+		this.dialog.set_values(copied);
+	}
+
 	get_linked_vouchers(document_types) {
 		frappe.call({
 			method:
@@ -75,10 +88,9 @@
 							row[1],
 							row[2],
 							reference_date,
-							row[8],
 							format_currency(row[3], row[9]),
-							row[6],
 							row[4],
+							row[6],
 						]);
 					});
 					this.get_dt_columns();
@@ -104,7 +116,7 @@
 			{
 				name: __("Document Name"),
 				editable: false,
-				width: 150,
+				width: 1,
 			},
 			{
 				name: __("Reference Date"),
@@ -112,25 +124,19 @@
 				width: 120,
 			},
 			{
-				name: "Posting Date",
-				editable: false,
-				width: 120,
-			},
-			{
-				name: __("Amount"),
+				name: __("Remaining"),
 				editable: false,
 				width: 100,
 			},
 			{
-				name: __("Party"),
-				editable: false,
-				width: 120,
-			},
-
-			{
 				name: __("Reference Number"),
 				editable: false,
-				width: 140,
+				width: 200,
+			},
+			{
+				name: __("Party"),
+				editable: false,
+				width: 100,
 			},
 		];
 	}
@@ -225,6 +231,16 @@
 				onchange: () => this.update_options(),
 			},
 			{
+				fieldname: "column_break_5",
+				fieldtype: "Column Break",
+			},
+			{
+				fieldtype: "Check",
+				label: "Bank Transaction",
+				fieldname: "bank_transaction",
+				onchange: () => this.update_options(),
+			},
+			{
 				fieldtype: "Section Break",
 				fieldname: "section_break_1",
 				label: __("Select Vouchers to Match"),
@@ -289,7 +305,7 @@
 				fieldtype: "Column Break",
 			},
 			{
-				default: "Journal Entry Type",
+				default: "Bank Entry",
 				fieldname: "journal_entry_type",
 				fieldtype: "Select",
 				label: "Journal Entry Type",
@@ -364,7 +380,12 @@
 				fieldtype: "Section Break",
 				fieldname: "details_section",
 				label: "Transaction Details",
-				collapsible: 1,
+			},
+			{
+				fieldname: "date",
+				fieldtype: "Date",
+				label: "Date",
+				read_only: 1,
 			},
 			{
 				fieldname: "deposit",
@@ -381,14 +402,14 @@
 				read_only: 1,
 			},
 			{
-				fieldname: "description",
-				fieldtype: "Small Text",
-				label: "Description",
+				fieldname: "column_break_17",
+				fieldtype: "Column Break",
 				read_only: 1,
 			},
 			{
-				fieldname: "column_break_17",
-				fieldtype: "Column Break",
+				fieldname: "description",
+				fieldtype: "Small Text",
+				label: "Description",
 				read_only: 1,
 			},
 			{
@@ -398,7 +419,6 @@
 				options: "Currency",
 				read_only: 1,
 			},
-
 			{
 				fieldname: "unallocated_amount",
 				fieldtype: "Currency",
@@ -593,4 +613,4 @@
 		}
 	}
 
-};
\ No newline at end of file
+};
diff --git a/erpnext/public/js/utils.js b/erpnext/public/js/utils.js
index 51dcd64..58aa8d7 100755
--- a/erpnext/public/js/utils.js
+++ b/erpnext/public/js/utils.js
@@ -221,9 +221,9 @@
 			callback: function(r) {
 				if (r.message && r.message.length) {
 					r.message.forEach((dimension) => {
-						let found = filters.some(el => el.fieldname === dimension['fieldname']);
+						let existing_filter = filters.filter(el => el.fieldname === dimension['fieldname']);
 
-						if (!found) {
+						if (!existing_filter.length) {
 							filters.splice(index, 0, {
 								"fieldname": dimension["fieldname"],
 								"label": __(dimension["doctype"]),
@@ -232,6 +232,11 @@
 									return frappe.db.get_link_options(dimension["doctype"], txt);
 								},
 							});
+						} else {
+							existing_filter[0]['fieldtype'] = "MultiSelectList";
+							existing_filter[0]['get_data'] = function(txt) {
+								return frappe.db.get_link_options(dimension["doctype"], txt);
+							}
 						}
 					});
 				}
diff --git a/erpnext/regional/doctype/ksa_vat_purchase_account/__init__.py b/erpnext/regional/doctype/ksa_vat_purchase_account/__init__.py
deleted file mode 100644
index e69de29..0000000
--- a/erpnext/regional/doctype/ksa_vat_purchase_account/__init__.py
+++ /dev/null
diff --git a/erpnext/regional/doctype/ksa_vat_purchase_account/ksa_vat_purchase_account.json b/erpnext/regional/doctype/ksa_vat_purchase_account/ksa_vat_purchase_account.json
deleted file mode 100644
index 89ba3e9..0000000
--- a/erpnext/regional/doctype/ksa_vat_purchase_account/ksa_vat_purchase_account.json
+++ /dev/null
@@ -1,49 +0,0 @@
-{
- "actions": [],
- "creation": "2021-07-13 09:17:09.862163",
- "doctype": "DocType",
- "editable_grid": 1,
- "engine": "InnoDB",
- "field_order": [
-  "title",
-  "item_tax_template",
-  "account"
- ],
- "fields": [
-  {
-   "fieldname": "account",
-   "fieldtype": "Link",
-   "in_list_view": 1,
-   "label": "Account",
-   "options": "Account",
-   "reqd": 1
-  },
-  {
-   "fieldname": "title",
-   "fieldtype": "Data",
-   "in_list_view": 1,
-   "label": "Title",
-   "reqd": 1
-  },
-  {
-   "fieldname": "item_tax_template",
-   "fieldtype": "Link",
-   "in_list_view": 1,
-   "label": "Item Tax Template",
-   "options": "Item Tax Template",
-   "reqd": 1
-  }
- ],
- "index_web_pages_for_search": 1,
- "istable": 1,
- "links": [],
- "modified": "2021-08-04 06:42:38.205597",
- "modified_by": "Administrator",
- "module": "Regional",
- "name": "KSA VAT Purchase Account",
- "owner": "Administrator",
- "permissions": [],
- "sort_field": "modified",
- "sort_order": "DESC",
- "track_changes": 1
-}
\ No newline at end of file
diff --git a/erpnext/regional/doctype/ksa_vat_purchase_account/ksa_vat_purchase_account.py b/erpnext/regional/doctype/ksa_vat_purchase_account/ksa_vat_purchase_account.py
deleted file mode 100644
index 3920bc5..0000000
--- a/erpnext/regional/doctype/ksa_vat_purchase_account/ksa_vat_purchase_account.py
+++ /dev/null
@@ -1,9 +0,0 @@
-# Copyright (c) 2021, Havenir Solutions and contributors
-# For license information, please see license.txt
-
-# import frappe
-from frappe.model.document import Document
-
-
-class KSAVATPurchaseAccount(Document):
-	pass
diff --git a/erpnext/regional/doctype/ksa_vat_sales_account/__init__.py b/erpnext/regional/doctype/ksa_vat_sales_account/__init__.py
deleted file mode 100644
index e69de29..0000000
--- a/erpnext/regional/doctype/ksa_vat_sales_account/__init__.py
+++ /dev/null
diff --git a/erpnext/regional/doctype/ksa_vat_sales_account/ksa_vat_sales_account.js b/erpnext/regional/doctype/ksa_vat_sales_account/ksa_vat_sales_account.js
deleted file mode 100644
index 72613f4..0000000
--- a/erpnext/regional/doctype/ksa_vat_sales_account/ksa_vat_sales_account.js
+++ /dev/null
@@ -1,8 +0,0 @@
-// Copyright (c) 2021, Havenir Solutions and contributors
-// For license information, please see license.txt
-
-frappe.ui.form.on('KSA VAT Sales Account', {
-	// refresh: function(frm) {
-
-	// }
-});
diff --git a/erpnext/regional/doctype/ksa_vat_sales_account/ksa_vat_sales_account.json b/erpnext/regional/doctype/ksa_vat_sales_account/ksa_vat_sales_account.json
deleted file mode 100644
index df27478..0000000
--- a/erpnext/regional/doctype/ksa_vat_sales_account/ksa_vat_sales_account.json
+++ /dev/null
@@ -1,49 +0,0 @@
-{
- "actions": [],
- "creation": "2021-07-13 08:46:33.820968",
- "doctype": "DocType",
- "editable_grid": 1,
- "engine": "InnoDB",
- "field_order": [
-  "title",
-  "item_tax_template",
-  "account"
- ],
- "fields": [
-  {
-   "fieldname": "account",
-   "fieldtype": "Link",
-   "in_list_view": 1,
-   "label": "Account",
-   "options": "Account",
-   "reqd": 1
-  },
-  {
-   "fieldname": "title",
-   "fieldtype": "Data",
-   "in_list_view": 1,
-   "label": "Title",
-   "reqd": 1
-  },
-  {
-   "fieldname": "item_tax_template",
-   "fieldtype": "Link",
-   "in_list_view": 1,
-   "label": "Item Tax Template",
-   "options": "Item Tax Template",
-   "reqd": 1
-  }
- ],
- "index_web_pages_for_search": 1,
- "istable": 1,
- "links": [],
- "modified": "2021-08-04 06:42:00.081407",
- "modified_by": "Administrator",
- "module": "Regional",
- "name": "KSA VAT Sales Account",
- "owner": "Administrator",
- "permissions": [],
- "sort_field": "modified",
- "sort_order": "DESC",
- "track_changes": 1
-}
\ No newline at end of file
diff --git a/erpnext/regional/doctype/ksa_vat_sales_account/ksa_vat_sales_account.py b/erpnext/regional/doctype/ksa_vat_sales_account/ksa_vat_sales_account.py
deleted file mode 100644
index 7c2689f..0000000
--- a/erpnext/regional/doctype/ksa_vat_sales_account/ksa_vat_sales_account.py
+++ /dev/null
@@ -1,9 +0,0 @@
-# Copyright (c) 2021, Havenir Solutions and contributors
-# For license information, please see license.txt
-
-# import frappe
-from frappe.model.document import Document
-
-
-class KSAVATSalesAccount(Document):
-	pass
diff --git a/erpnext/regional/doctype/ksa_vat_sales_account/test_ksa_vat_sales_account.py b/erpnext/regional/doctype/ksa_vat_sales_account/test_ksa_vat_sales_account.py
deleted file mode 100644
index 1d6a6a7..0000000
--- a/erpnext/regional/doctype/ksa_vat_sales_account/test_ksa_vat_sales_account.py
+++ /dev/null
@@ -1,9 +0,0 @@
-# Copyright (c) 2021, Havenir Solutions and Contributors
-# See license.txt
-
-# import frappe
-import unittest
-
-
-class TestKSAVATSalesAccount(unittest.TestCase):
-	pass
diff --git a/erpnext/regional/doctype/ksa_vat_setting/__init__.py b/erpnext/regional/doctype/ksa_vat_setting/__init__.py
deleted file mode 100644
index e69de29..0000000
--- a/erpnext/regional/doctype/ksa_vat_setting/__init__.py
+++ /dev/null
diff --git a/erpnext/regional/doctype/ksa_vat_setting/ksa_vat_setting.js b/erpnext/regional/doctype/ksa_vat_setting/ksa_vat_setting.js
deleted file mode 100644
index 00b62b9..0000000
--- a/erpnext/regional/doctype/ksa_vat_setting/ksa_vat_setting.js
+++ /dev/null
@@ -1,8 +0,0 @@
-// Copyright (c) 2021, Havenir Solutions and contributors
-// For license information, please see license.txt
-
-frappe.ui.form.on('KSA VAT Setting', {
-	onload: function () {
-		frappe.breadcrumbs.add('Accounts', 'KSA VAT Setting');
-	}
-});
diff --git a/erpnext/regional/doctype/ksa_vat_setting/ksa_vat_setting.json b/erpnext/regional/doctype/ksa_vat_setting/ksa_vat_setting.json
deleted file mode 100644
index 3361946..0000000
--- a/erpnext/regional/doctype/ksa_vat_setting/ksa_vat_setting.json
+++ /dev/null
@@ -1,49 +0,0 @@
-{
- "actions": [],
- "autoname": "field:company",
- "creation": "2021-07-13 08:49:01.100356",
- "doctype": "DocType",
- "editable_grid": 1,
- "engine": "InnoDB",
- "field_order": [
-  "company",
-  "ksa_vat_sales_accounts",
-  "ksa_vat_purchase_accounts"
- ],
- "fields": [
-  {
-   "fieldname": "company",
-   "fieldtype": "Link",
-   "in_list_view": 1,
-   "label": "Company",
-   "options": "Company",
-   "reqd": 1,
-   "unique": 1
-  },
-  {
-   "fieldname": "ksa_vat_sales_accounts",
-   "fieldtype": "Table",
-   "label": "KSA VAT Sales Accounts",
-   "options": "KSA VAT Sales Account",
-   "reqd": 1
-  },
-  {
-   "fieldname": "ksa_vat_purchase_accounts",
-   "fieldtype": "Table",
-   "label": "KSA VAT Purchase Accounts",
-   "options": "KSA VAT Purchase Account",
-   "reqd": 1
-  }
- ],
- "links": [],
- "modified": "2021-08-26 04:29:06.499378",
- "modified_by": "Administrator",
- "module": "Regional",
- "name": "KSA VAT Setting",
- "owner": "Administrator",
- "permissions": [],
- "sort_field": "modified",
- "sort_order": "DESC",
- "title_field": "company",
- "track_changes": 1
-}
\ No newline at end of file
diff --git a/erpnext/regional/doctype/ksa_vat_setting/ksa_vat_setting.py b/erpnext/regional/doctype/ksa_vat_setting/ksa_vat_setting.py
deleted file mode 100644
index bdae116..0000000
--- a/erpnext/regional/doctype/ksa_vat_setting/ksa_vat_setting.py
+++ /dev/null
@@ -1,9 +0,0 @@
-# Copyright (c) 2021, Havenir Solutions and contributors
-# For license information, please see license.txt
-
-# import frappe
-from frappe.model.document import Document
-
-
-class KSAVATSetting(Document):
-	pass
diff --git a/erpnext/regional/doctype/ksa_vat_setting/ksa_vat_setting_list.js b/erpnext/regional/doctype/ksa_vat_setting/ksa_vat_setting_list.js
deleted file mode 100644
index 269cbec..0000000
--- a/erpnext/regional/doctype/ksa_vat_setting/ksa_vat_setting_list.js
+++ /dev/null
@@ -1,5 +0,0 @@
-frappe.listview_settings['KSA VAT Setting'] = {
-	onload () {
-		frappe.breadcrumbs.add('Accounts');
-	}
-}
\ No newline at end of file
diff --git a/erpnext/regional/doctype/ksa_vat_setting/test_ksa_vat_setting.py b/erpnext/regional/doctype/ksa_vat_setting/test_ksa_vat_setting.py
deleted file mode 100644
index 7207901..0000000
--- a/erpnext/regional/doctype/ksa_vat_setting/test_ksa_vat_setting.py
+++ /dev/null
@@ -1,9 +0,0 @@
-# Copyright (c) 2021, Havenir Solutions and Contributors
-# See license.txt
-
-# import frappe
-import unittest
-
-
-class TestKSAVATSetting(unittest.TestCase):
-	pass
diff --git a/erpnext/regional/print_format/ksa_pos_invoice/__init__.py b/erpnext/regional/print_format/ksa_pos_invoice/__init__.py
deleted file mode 100644
index e69de29..0000000
--- a/erpnext/regional/print_format/ksa_pos_invoice/__init__.py
+++ /dev/null
diff --git a/erpnext/regional/print_format/ksa_pos_invoice/ksa_pos_invoice.json b/erpnext/regional/print_format/ksa_pos_invoice/ksa_pos_invoice.json
deleted file mode 100644
index c2a3092..0000000
--- a/erpnext/regional/print_format/ksa_pos_invoice/ksa_pos_invoice.json
+++ /dev/null
@@ -1,32 +0,0 @@
-{
- "absolute_value": 0,
- "align_labels_right": 0,
- "creation": "2021-12-07 13:25:05.424827",
- "css": "",
- "custom_format": 1,
- "default_print_language": "en",
- "disabled": 1,
- "doc_type": "POS Invoice",
- "docstatus": 0,
- "doctype": "Print Format",
- "font_size": 0,
- "html": "<style>\n\t.print-format table, .print-format tr, \n\t.print-format td, .print-format div, .print-format p {\n\t\tline-height: 150%;\n\t\tvertical-align: middle;\n\t}\n\t@media screen {\n\t\t.print-format {\n\t\t\twidth: 4in;\n\t\t\tpadding: 0.25in;\n\t\t\tmin-height: 8in;\n\t\t}\n\t}\n</style>\n\n{% if letter_head %}\n    {{ letter_head }}\n{% endif %}\n\n<p class=\"text-center\" style=\"margin-bottom: 1rem\">\n\t{{ doc.company }}<br>\n\t<b>{{ doc.select_print_heading or _(\"Invoice\") }}</b><br>\n\t<img src={{doc.ksa_einv_qr}}>\n</p>\n<p>\n\t<b>{{ _(\"Receipt No\") }}:</b> {{ doc.name }}<br>\n\t<b>{{ _(\"Cashier\") }}:</b> {{ doc.owner }}<br>\n\t<b>{{ _(\"Customer\") }}:</b> {{ doc.customer_name }}<br>\n\t<b>{{ _(\"Date\") }}:</b> {{ doc.get_formatted(\"posting_date\") }}<br>\n\t<b>{{ _(\"Time\") }}:</b> {{  doc.get_formatted(\"posting_time\") }}<br>\n</p>\n\n<hr>\n<table class=\"table table-condensed\">\n\t<thead>\n\t\t<tr>\n\t\t\t<th width=\"40%\">{{ _(\"Item\") }}</th>\n\t\t\t<th width=\"25%\" class=\"text-right\">{{ _(\"Qty\") }}</th>\n\t\t\t<th width=\"35%\" class=\"text-right\">{{ _(\"Amount\") }}</th>\n\t\t</tr>\n\t</thead>\n\t<tbody>\n\t\t{%- for item in doc.items -%}\n\t\t<tr>\n\t\t\t<td>\n\t\t\t\t{{ item.item_code }}\n\t\t\t\t{%- if item.item_name != item.item_code -%}\n\t\t\t\t\t<br>{{ item.item_name }}\n\t\t\t\t{%- endif -%}\n\t\t\t\t{%- if item.serial_no -%}\n\t\t\t\t\t<br><b>{{ _(\"SR.No\") }}:</b><br>\n\t\t\t\t\t{{ item.serial_no | replace(\"\\n\", \", \") }}\n\t\t\t\t{%- endif -%}\n\t\t\t</td>\n\t\t\t<td class=\"text-right\">{{ item.qty }}</td>\n\t\t\t<td class=\"text-right\">{{ item.get_formatted(\"net_amount\") }}</td>\n\t\t</tr>\n\t\t{%- endfor -%}\n\t</tbody>\n</table>\n<table class=\"table table-condensed no-border\">\n\t<tbody>\n\t\t<tr>\n\t\t\t<td class=\"text-right\" style=\"width: 60%\">\n\t\t\t\t{{ _(\"Total Excl. Tax\") }}\n\t\t\t</td>\n\t\t\t<td class=\"text-right\">\n\t\t\t\t{{ doc.get_formatted(\"net_total\", doc) }}\n\t\t\t</td>\n\t\t</tr>\n\t\t{%- for row in doc.taxes -%}\n\t\t\t<tr>\n\t\t\t\t<td class=\"text-right\" style=\"width: 60%\">\n\t\t\t\t    {% if '%' in row.description %}\n\t\t\t\t\t    {{ row.description }}\n\t\t\t\t\t{% else %}\n\t\t\t\t\t    {{ row.description }}@{{ row.rate }}%\n\t\t\t\t\t{% endif %}\n\t\t\t\t</td>\n\t\t\t\t<td class=\"text-right\">\n\t\t\t\t\t{{ row.get_formatted(\"tax_amount\", doc) }}\n\t\t\t\t</td>\n\t\t\t<tr>\n\t\t{%- endfor -%}\n\n\t\t{%- if doc.discount_amount -%}\n\t\t<tr>\n\t\t\t<td class=\"text-right\" style=\"width: 60%\">\n\t\t\t\t{{ _(\"Discount\") }}\n\t\t\t</td>\n\t\t\t<td class=\"text-right\">\n\t\t\t\t{{ doc.get_formatted(\"discount_amount\") }}\n\t\t\t</td>\n\t\t</tr>\n\t\t{%- endif -%}\n\t\t<tr>\n\t\t\t<td class=\"text-right\" style=\"width: 60%\">\n\t\t\t\t<b>{{ _(\"Grand Total\") }}</b>\n\t\t\t</td>\n\t\t\t<td class=\"text-right\">\n\t\t\t\t{{ doc.get_formatted(\"grand_total\") }}\n\t\t\t</td>\n\t\t</tr>\n\t\t{%- if doc.rounded_total -%}\n\t\t<tr>\n\t\t\t<td class=\"text-right\" style=\"width: 60%\">\n\t\t\t\t<b>{{ _(\"Rounded Total\") }}</b>\n\t\t\t</td>\n\t\t\t<td class=\"text-right\">\n\t\t\t\t{{ doc.get_formatted(\"rounded_total\") }}\n\t\t\t</td>\n\t\t</tr>\n\t\t{%- endif -%}\n\t\t<tr>\n\t\t\t<td class=\"text-right\" style=\"width: 60%\">\n\t\t\t\t<b>{{ _(\"Paid Amount\") }}</b>\n\t\t\t</td>\n\t\t\t<td class=\"text-right\">\n\t\t\t\t{{ doc.get_formatted(\"paid_amount\") }}\n\t\t\t</td>\n\t\t</tr>\n\t\t{%- if doc.change_amount -%}\n\t\t\t<tr>\n\t\t\t\t<td class=\"text-right\" style=\"width: 60%\">\n\t\t\t\t\t<b>{{ _(\"Change Amount\") }}</b>\n\t\t\t\t</td>\n\t\t\t\t<td class=\"text-right\">\n\t\t\t\t\t{{ doc.get_formatted(\"change_amount\") }}\n\t\t\t\t</td>\n\t\t\t</tr>\n\t\t{%- endif -%}\n\t</tbody>\n</table>\n<hr>\n<p>{{ doc.terms or \"\" }}</p>\n<p class=\"text-center\">{{ _(\"Thank you, please visit again.\") }}</p>",
- "idx": 0,
- "line_breaks": 0,
- "margin_bottom": 0.0,
- "margin_left": 0.0,
- "margin_right": 0.0,
- "margin_top": 0.0,
- "modified": "2021-12-08 10:25:01.930885",
- "modified_by": "Administrator",
- "module": "Regional",
- "name": "KSA POS Invoice",
- "owner": "Administrator",
- "page_number": "Hide",
- "print_format_builder": 0,
- "print_format_builder_beta": 0,
- "print_format_type": "Jinja",
- "raw_printing": 0,
- "show_section_headings": 0,
- "standard": "Yes"
-}
\ No newline at end of file
diff --git a/erpnext/regional/print_format/ksa_vat_invoice/__init__.py b/erpnext/regional/print_format/ksa_vat_invoice/__init__.py
deleted file mode 100644
index e69de29..0000000
--- a/erpnext/regional/print_format/ksa_vat_invoice/__init__.py
+++ /dev/null
diff --git a/erpnext/regional/print_format/ksa_vat_invoice/ksa_vat_invoice.json b/erpnext/regional/print_format/ksa_vat_invoice/ksa_vat_invoice.json
deleted file mode 100644
index 6b64d47..0000000
--- a/erpnext/regional/print_format/ksa_vat_invoice/ksa_vat_invoice.json
+++ /dev/null
@@ -1,32 +0,0 @@
-{
- "absolute_value": 0,
- "align_labels_right": 0,
- "creation": "2021-10-29 22:46:26.039023",
- "css": ".qr-code{\n    float:right;\n}\n\n.invoice-heading {\n  margin: 0;\n}\n\n.ksa-invoice-table {\n  border: 1px solid #888a8e;\n  border-collapse: collapse;\n  width: 100%;\n  margin: 20px 0;\n  font-size: 16px;\n}\n\n.ksa-invoice-table.two-columns td:nth-child(2) {\n  direction: rtl;\n}\n\n.ksa-invoice-table th {\n  border: 1px solid #888a8e;\n  max-width: 50%;\n  padding: 8px;\n}\n\n.ksa-invoice-table td {\n  padding: 5px;\n  border: 1px solid #888a8e;\n  max-width: 50%;\n}\n\n.ksa-invoice-table thead,\n.ksa-invoice-table tfoot {\n  text-transform: uppercase;\n}\n\n.qr-rtl {\n  direction: rtl;\n}\n\n.qr-flex{\n    display: flex;\n    justify-content: space-between;\n}",
- "custom_format": 1,
- "default_print_language": "en",
- "disabled": 1,
- "doc_type": "Sales Invoice",
- "docstatus": 0,
- "doctype": "Print Format",
- "font_size": 14,
- "html": "<div class=\"ksa-vat-format\">\n    <div class=\"qr-flex\">\n        <div style=\"qr-flex: 1\">\n            <h2 class=\"invoice-heading\">TAX INVOICE</h2>\n            <h2 class=\"invoice-heading\">\u0641\u0627\u062a\u0648\u0631\u0629 \u0636\u0631\u064a\u0628\u064a\u0629</h2>\n        </div>\n        \n        <img class=\"qr-code\" src={{doc.ksa_einv_qr}}>\n    </div>\n    {% set company = frappe.get_doc(\"Company\", doc.company)%}\n    {% if (doc.company_address) %}\n        {% set supplier_address_doc = frappe.get_doc('Address', doc.company_address) %}\n    {% endif %}\n    \n    {% if(doc.customer_address) %}\n        {% set customer_address = frappe.get_doc('Address', doc.customer_address ) %}\n    {% endif %}\n    \n    {% if(doc.shipping_address_name) %}\n        {% set customer_shipping_address = frappe.get_doc('Address', doc.shipping_address_name ) %}\n    {% endif %}  \n        \n    <table class=\"ksa-invoice-table two-columns\">\n      <thead>\n        <tr>\n          <th>{{ company.name }}</th>\n          <th style=\"text-align: right;\">{{ company.company_name_in_arabic }}</th>\n        </tr>\n      </thead>\n\n      <tbody>\n        <!-- Invoice Info -->\n        <tr>\n          <td>Invoice#: {{doc.name}}</td>\n          <td>\u0631\u0642\u0645 \u0627\u0644\u0641\u0627\u062a\u0648\u0631\u0629: {{doc.name}}</td>\n        </tr>\n        <tr>\n          <td>Invoice Date: {{doc.posting_date}}</td>\n          <td>\u062a\u0627\u0631\u064a\u062e \u0627\u0644\u0641\u0627\u062a\u0648\u0631\u0629: {{doc.posting_date}}</td>\n        </tr>\n        <tr>\n          <td>Date of Supply:{{doc.posting_date}}</td>\n          <td>\u062a\u0627\u0631\u064a\u062e \u0627\u0644\u062a\u0648\u0631\u064a\u062f: {{doc.posting_date}}</td>\n        </tr>\n        \n        <!--Supplier Info -->\n        <tr>\n          <td>Supplier:</td>\n          <td>\u0627\u0644\u0645\u0648\u0631\u062f:</td>\n        </tr>\n\t\t{% if (company.tax_id) %}\n        <tr>\n          <td>Supplier Tax Identification Number:</td>\n          <td>\u0631\u0642\u0645 \u0627\u0644\u062a\u0639\u0631\u064a\u0641 \u0627\u0644\u0636\u0631\u064a\u0628\u064a \u0644\u0644\u0645\u0648\u0631\u062f:</td>\n        </tr>\n        <tr>\n          <td>{{ company.tax_id }}</td>\n          <td>{{ company.tax_id }}</td>\n        </tr>\n        {% endif %}\n        <tr>\n          <td>{{ company.name }}</td>\n          <td>{{ company.company_name_in_arabic }} </td>\n        </tr>\n        \n        \n        {% if(supplier_address_doc) %}\n        <tr>\n          <td>{{ supplier_address_doc.address_line1}} </td>\n          <td>{{ supplier_address_doc.address_in_arabic}} </td>\n        </tr>\n        <tr>\n          <td>Phone: {{ supplier_address_doc.phone }}</td>\n          <td>\u0647\u0627\u062a\u0641: {{ supplier_address_doc.phone }}</td>\n        </tr>\n        <tr>\n          <td>Email: {{ supplier_address_doc.email_id }}</td>\n          <td>\u0628\u0631\u064a\u062f \u0627\u0644\u0643\u062a\u0631\u0648\u0646\u064a: {{ supplier_address_doc.email_id }}</td>\n        </tr>\n        {% endif %}\n        \n        <!-- Customer Info -->\n        <tr>\n          <td>CUSTOMER:</td>\n          <td>\u0639\u0645\u064a\u0644:</td>\n        </tr>\n\t\t{% set customer_tax_id = frappe.db.get_value('Customer', doc.customer, 'tax_id') %}\n\t\t{% if customer_tax_id %}\n        <tr>\n          <td>Customer Tax Identification Number:</td>\n          <td>\u0631\u0642\u0645 \u0627\u0644\u062a\u0639\u0631\u064a\u0641 \u0627\u0644\u0636\u0631\u064a\u0628\u064a \u0644\u0644\u0639\u0645\u064a\u0644:</td>\n        </tr>\n        <tr>\n          <td>{{ customer_tax_id }}</td>\n          <td>{{ customer_tax_id }}</td>\n        </tr>\n        {% endif %}\n        <tr>\n          <td> {{ doc.customer }}</td>\n          <td> {{ doc.customer_name_in_arabic }} </td>\n        </tr>\n        \n        {% if(customer_address) %}\n        <tr>\n          <td>{{ customer_address.address_line1}} </td>\n          <td>{{ customer_address.address_in_arabic}} </td>\n        </tr>\n        {% endif %}\n        \n        {% if(customer_shipping_address) %}\n        <tr>\n          <td>SHIPPING ADDRESS:</td>\n          <td>\u0639\u0646\u0648\u0627\u0646 \u0627\u0644\u0634\u062d\u0646:</td>\n        </tr>\n        \n        <tr>\n          <td>{{ customer_shipping_address.address_line1}} </td>\n          <td>{{ customer_shipping_address.address_in_arabic}} </td>\n        </tr>\n        {% endif %}\n        \n\t\t{% if(doc.po_no) %}\n        <tr>\n          <td>OTHER INFORMATION</td>\n          <td>\u0645\u0639\u0644\u0648\u0645\u0627\u062a \u0623\u062e\u0631\u0649</td>\n        </tr>\n        \n        <tr>\n          <td>Purchase Order Number: {{ doc.po_no }}</td>\n          <td>\u0631\u0642\u0645 \u0623\u0645\u0631 \u0627\u0644\u0634\u0631\u0627\u0621: {{ doc.po_no }}</td>\n        </tr>\n        {% endif %}\n        \n        <tr>\n          <td>Payment Due Date: {{  doc.due_date}} </td>\n          <td>\u062a\u0627\u0631\u064a\u062e \u0627\u0633\u062a\u062d\u0642\u0627\u0642 \u0627\u0644\u062f\u0641\u0639: {{  doc.due_date}}</td>\n        </tr>\n      </tbody>\n    </table>\n\n    <!--Dynamic Colspan for total row columns-->\n    {% set col = namespace(one = 2, two = 1) %}\n    {% set length = doc.taxes | length %}\n    {% set length = length / 2 | round %}\n    {% set col.one = col.one + length %}\n    {% set col.two = col.two + length %}\n  \n    {%- if(doc.taxes | length % 2 > 0 ) -%}\n      {% set col.two = col.two + 1 %}\n    {% endif %}\n    \n    <!-- Items -->\n    {% set total = namespace(amount = 0) %}\n    <table class=\"ksa-invoice-table\">\n      <thead>\n        <tr>\n          <th>Nature of goods or services <br />\u0637\u0628\u064a\u0639\u0629 \u0627\u0644\u0633\u0644\u0639 \u0623\u0648 \u0627\u0644\u062e\u062f\u0645\u0627\u062a</th>\n          <th>\n            Unit price <br />\n            \u0633\u0639\u0631 \u0627\u0644\u0648\u062d\u062f\u0629\n          </th>\n          <th>\n            Quantity <br />\n            \u0627\u0644\u0643\u0645\u064a\u0629\n          </th>\n          <th>\n            Taxable Amount <br />\n            \u0627\u0644\u0645\u0628\u0644\u063a \u0627\u0644\u062e\u0627\u0636\u0639 \u0644\u0644\u0636\u0631\u064a\u0628\u0629\n          </th>\n          \n          {% for row in doc.taxes %}\n            <th style=\"min-width: 130px\">{{row.description}}</th>\n          {% endfor %}\n          \n          <th>\n            Total <br />\n            \u0627\u0644\u0645\u062c\u0645\u0648\u0639\n          </th>\n        </tr>\n      </thead>\n      <tbody>\n        {%- for item in doc.items -%}\n        {% set total.amount = item.amount %}\n        <tr>\n          <td>{{ item.item_code or item.item_name }}</td>\n          <td>{{ item.get_formatted(\"rate\") }}</td>\n          <td>{{ item.qty }}</td>\n          <td>{{ item.get_formatted(\"amount\") }}</td>\n           {% for row in doc.taxes %}\n                {% set data_object = json.loads(row.item_wise_tax_detail) %}\n                {% set key = item.item_code or item.item_name %}\n                {% set tax_amount = frappe.utils.flt(data_object[key][1]/doc.conversion_rate, row.precision('tax_amount')) %}\n                <td>\n                   <div class=\"qr-flex\">\n                    {%- if(data_object[key][0])-%}\n                    <span>{{ frappe.format(data_object[key][0], {'fieldtype': 'Percent'}) }}</span>\n                    {%- endif -%}\n                    <span>\n                    {%- if(data_object[key][1])-%}\n                        {{ frappe.format_value(tax_amount, currency=doc.currency) }}</span>\n                        {% set total.amount = total.amount + tax_amount %}\n                    {%- endif -%}\n                    </div>\n                </td>\n            {% endfor %}\n          <td>{{  frappe.format_value(frappe.utils.flt(total.amount, doc.precision('total_taxes_and_charges')), currency=doc.currency) }}</td>\n        </tr>\n        {%- endfor -%}\n      </tbody>\n      <tfoot>\n        <tr>\n          <td>\n            {{ doc.get_formatted(\"total\") }} <br />\n            {{ doc.get_formatted(\"total_taxes_and_charges\") }}\n          </td>\n          \n          <td colspan={{ col.one }} class=\"qr-rtl\">\n            \u0627\u0644\u0625\u062c\u0645\u0627\u0644\u064a \u0628\u0627\u0633\u062a\u062b\u0646\u0627\u0621 \u0636\u0631\u064a\u0628\u0629 \u0627\u0644\u0642\u064a\u0645\u0629 \u0627\u0644\u0645\u0636\u0627\u0641\u0629\n            <br />\n            \u0625\u062c\u0645\u0627\u0644\u064a \u0636\u0631\u064a\u0628\u0629 \u0627\u0644\u0642\u064a\u0645\u0629 \u0627\u0644\u0645\u0636\u0627\u0641\u0629\n          </td>\n          <td colspan={{ col.two }}>\n            Total (Excluding VAT)\n            <br />\n            Total VAT\n          </td>\n          <td>\n            {{ doc.get_formatted(\"total\") }} <br />\n            {{ doc.get_formatted(\"total_taxes_and_charges\") }}\n          </td>\n        </tr>\n        <tr>\n          <td>{{ doc.get_formatted(\"grand_total\") }}</td>\n          <td  colspan={{  col.one }} class=\"qr-rtl\">\n              \u0625\u062c\u0645\u0627\u0644\u064a \u0627\u0644\u0645\u0628\u0644\u063a \u0627\u0644\u0645\u0633\u062a\u062d\u0642</td>\n          <td  colspan={{  col.two }}>Total Amount Due</td>\n          <td>{{ doc.get_formatted(\"grand_total\") }}</td>\n        </tr>\n      </tfoot>\n    </table>\n\n\t{%- if doc.terms -%}\n    <p>\n      {{doc.terms}}\n    </p>\n\t{%- endif -%}\n</div>\n",
- "idx": 0,
- "line_breaks": 0,
- "margin_bottom": 15.0,
- "margin_left": 15.0,
- "margin_right": 15.0,
- "margin_top": 15.0,
- "modified": "2021-12-07 13:43:38.018593",
- "modified_by": "Administrator",
- "module": "Regional",
- "name": "KSA VAT Invoice",
- "owner": "Administrator",
- "page_number": "Hide",
- "print_format_builder": 0,
- "print_format_builder_beta": 0,
- "print_format_type": "Jinja",
- "raw_printing": 0,
- "show_section_headings": 0,
- "standard": "Yes"
-}
\ No newline at end of file
diff --git a/erpnext/regional/report/ksa_vat/__init__.py b/erpnext/regional/report/ksa_vat/__init__.py
deleted file mode 100644
index e69de29..0000000
--- a/erpnext/regional/report/ksa_vat/__init__.py
+++ /dev/null
diff --git a/erpnext/regional/report/ksa_vat/ksa_vat.js b/erpnext/regional/report/ksa_vat/ksa_vat.js
deleted file mode 100644
index 59e72c3..0000000
--- a/erpnext/regional/report/ksa_vat/ksa_vat.js
+++ /dev/null
@@ -1,59 +0,0 @@
-// Copyright (c) 2016, Havenir Solutions and contributors
-// For license information, please see license.txt
-/* eslint-disable */
-
-frappe.query_reports["KSA VAT"] = {
-	onload() {
-		frappe.breadcrumbs.add('Accounts');
-	},
-	"filters": [
-		{
-			"fieldname": "company",
-			"label": __("Company"),
-			"fieldtype": "Link",
-			"options": "Company",
-			"reqd": 1,
-			"default": frappe.defaults.get_user_default("Company")
-		},
-		{
-			"fieldname": "from_date",
-			"label": __("From Date"),
-			"fieldtype": "Date",
-			"reqd": 1,
-			"default": frappe.datetime.add_months(frappe.datetime.get_today(), -1),
-		},
-		{
-			"fieldname": "to_date",
-			"label": __("To Date"),
-			"fieldtype": "Date",
-			"reqd": 1,
-			"default": frappe.datetime.get_today()
-		}
-	],
-	"formatter": function(value, row, column, data, default_formatter) {
-		if (data
-			&& (data.title=='VAT on Sales' || data.title=='VAT on Purchases')
-			&& data.title==value) {
-			value = $(`<span>${value}</span>`);
-			var $value = $(value).css("font-weight", "bold");
-			value = $value.wrap("<p></p>").parent().html();
-			return value
-		}else if (data.title=='Grand Total'){
-			if (data.title==value) {
-				value = $(`<span>${value}</span>`);
-				var $value = $(value).css("font-weight", "bold");
-				value = $value.wrap("<p></p>").parent().html();
-				return value
-			}else{
-				value = default_formatter(value, row, column, data);
-				value = $(`<span>${value}</span>`);
-				var $value = $(value).css("font-weight", "bold");
-				value = $value.wrap("<p></p>").parent().html();
-				return value
-			}
-		}else{
-			value = default_formatter(value, row, column, data);
-			return value;
-		}
-	},
-};
diff --git a/erpnext/regional/report/ksa_vat/ksa_vat.json b/erpnext/regional/report/ksa_vat/ksa_vat.json
deleted file mode 100644
index 036e260..0000000
--- a/erpnext/regional/report/ksa_vat/ksa_vat.json
+++ /dev/null
@@ -1,32 +0,0 @@
-{
- "add_total_row": 0,
- "columns": [],
- "creation": "2021-07-13 08:54:38.000949",
- "disable_prepared_report": 1,
- "disabled": 1,
- "docstatus": 0,
- "doctype": "Report",
- "filters": [],
- "idx": 0,
- "is_standard": "Yes",
- "modified": "2021-08-26 04:14:37.202594",
- "modified_by": "Administrator",
- "module": "Regional",
- "name": "KSA VAT",
- "owner": "Administrator",
- "prepared_report": 1,
- "ref_doctype": "GL Entry",
- "report_name": "KSA VAT",
- "report_type": "Script Report",
- "roles": [
-  {
-   "role": "System Manager"
-  },
-  {
-   "role": "Accounts Manager"
-  },
-  {
-   "role": "Accounts User"
-  }
- ]
-}
\ No newline at end of file
diff --git a/erpnext/regional/report/ksa_vat/ksa_vat.py b/erpnext/regional/report/ksa_vat/ksa_vat.py
deleted file mode 100644
index 15996d2..0000000
--- a/erpnext/regional/report/ksa_vat/ksa_vat.py
+++ /dev/null
@@ -1,231 +0,0 @@
-# Copyright (c) 2013, Havenir Solutions and contributors
-# For license information, please see license.txt
-
-
-import json
-
-import frappe
-from frappe import _
-from frappe.utils import get_url_to_list
-
-
-def execute(filters=None):
-	columns = columns = get_columns()
-	data = get_data(filters)
-	return columns, data
-
-
-def get_columns():
-	return [
-		{
-			"fieldname": "title",
-			"label": _("Title"),
-			"fieldtype": "Data",
-			"width": 300,
-		},
-		{
-			"fieldname": "amount",
-			"label": _("Amount (SAR)"),
-			"fieldtype": "Currency",
-			"options": "currency",
-			"width": 150,
-		},
-		{
-			"fieldname": "adjustment_amount",
-			"label": _("Adjustment (SAR)"),
-			"fieldtype": "Currency",
-			"options": "currency",
-			"width": 150,
-		},
-		{
-			"fieldname": "vat_amount",
-			"label": _("VAT Amount (SAR)"),
-			"fieldtype": "Currency",
-			"options": "currency",
-			"width": 150,
-		},
-		{
-			"fieldname": "currency",
-			"label": _("Currency"),
-			"fieldtype": "Currency",
-			"width": 150,
-			"hidden": 1,
-		},
-	]
-
-
-def get_data(filters):
-	data = []
-
-	# Validate if vat settings exist
-	company = filters.get("company")
-	company_currency = frappe.get_cached_value("Company", company, "default_currency")
-
-	if frappe.db.exists("KSA VAT Setting", company) is None:
-		url = get_url_to_list("KSA VAT Setting")
-		frappe.msgprint(_('Create <a href="{}">KSA VAT Setting</a> for this company').format(url))
-		return data
-
-	ksa_vat_setting = frappe.get_doc("KSA VAT Setting", company)
-
-	# Sales Heading
-	append_data(data, "VAT on Sales", "", "", "", company_currency)
-
-	grand_total_taxable_amount = 0
-	grand_total_taxable_adjustment_amount = 0
-	grand_total_tax = 0
-
-	for vat_setting in ksa_vat_setting.ksa_vat_sales_accounts:
-		(
-			total_taxable_amount,
-			total_taxable_adjustment_amount,
-			total_tax,
-		) = get_tax_data_for_each_vat_setting(vat_setting, filters, "Sales Invoice")
-
-		# Adding results to data
-		append_data(
-			data,
-			vat_setting.title,
-			total_taxable_amount,
-			total_taxable_adjustment_amount,
-			total_tax,
-			company_currency,
-		)
-
-		grand_total_taxable_amount += total_taxable_amount
-		grand_total_taxable_adjustment_amount += total_taxable_adjustment_amount
-		grand_total_tax += total_tax
-
-	# Sales Grand Total
-	append_data(
-		data,
-		"Grand Total",
-		grand_total_taxable_amount,
-		grand_total_taxable_adjustment_amount,
-		grand_total_tax,
-		company_currency,
-	)
-
-	# Blank Line
-	append_data(data, "", "", "", "", company_currency)
-
-	# Purchase Heading
-	append_data(data, "VAT on Purchases", "", "", "", company_currency)
-
-	grand_total_taxable_amount = 0
-	grand_total_taxable_adjustment_amount = 0
-	grand_total_tax = 0
-
-	for vat_setting in ksa_vat_setting.ksa_vat_purchase_accounts:
-		(
-			total_taxable_amount,
-			total_taxable_adjustment_amount,
-			total_tax,
-		) = get_tax_data_for_each_vat_setting(vat_setting, filters, "Purchase Invoice")
-
-		# Adding results to data
-		append_data(
-			data,
-			vat_setting.title,
-			total_taxable_amount,
-			total_taxable_adjustment_amount,
-			total_tax,
-			company_currency,
-		)
-
-		grand_total_taxable_amount += total_taxable_amount
-		grand_total_taxable_adjustment_amount += total_taxable_adjustment_amount
-		grand_total_tax += total_tax
-
-	# Purchase Grand Total
-	append_data(
-		data,
-		"Grand Total",
-		grand_total_taxable_amount,
-		grand_total_taxable_adjustment_amount,
-		grand_total_tax,
-		company_currency,
-	)
-
-	return data
-
-
-def get_tax_data_for_each_vat_setting(vat_setting, filters, doctype):
-	"""
-	(KSA, {filters}, 'Sales Invoice') => 500, 153, 10 \n
-	calculates and returns \n
-	total_taxable_amount, total_taxable_adjustment_amount, total_tax"""
-	from_date = filters.get("from_date")
-	to_date = filters.get("to_date")
-
-	# Initiate variables
-	total_taxable_amount = 0
-	total_taxable_adjustment_amount = 0
-	total_tax = 0
-	# Fetch All Invoices
-	invoices = frappe.get_all(
-		doctype,
-		filters={"docstatus": 1, "posting_date": ["between", [from_date, to_date]]},
-		fields=["name", "is_return"],
-	)
-
-	for invoice in invoices:
-		invoice_items = frappe.get_all(
-			f"{doctype} Item",
-			filters={
-				"docstatus": 1,
-				"parent": invoice.name,
-				"item_tax_template": vat_setting.item_tax_template,
-			},
-			fields=["item_code", "net_amount"],
-		)
-
-		for item in invoice_items:
-			# Summing up total taxable amount
-			if invoice.is_return == 0:
-				total_taxable_amount += item.net_amount
-
-			if invoice.is_return == 1:
-				total_taxable_adjustment_amount += item.net_amount
-
-			# Summing up total tax
-			total_tax += get_tax_amount(item.item_code, vat_setting.account, doctype, invoice.name)
-
-	return total_taxable_amount, total_taxable_adjustment_amount, total_tax
-
-
-def append_data(data, title, amount, adjustment_amount, vat_amount, company_currency):
-	"""Returns data with appended value."""
-	data.append(
-		{
-			"title": _(title),
-			"amount": amount,
-			"adjustment_amount": adjustment_amount,
-			"vat_amount": vat_amount,
-			"currency": company_currency,
-		}
-	)
-
-
-def get_tax_amount(item_code, account_head, doctype, parent):
-	if doctype == "Sales Invoice":
-		tax_doctype = "Sales Taxes and Charges"
-
-	elif doctype == "Purchase Invoice":
-		tax_doctype = "Purchase Taxes and Charges"
-
-	item_wise_tax_detail = frappe.get_value(
-		tax_doctype,
-		{"docstatus": 1, "parent": parent, "account_head": account_head},
-		"item_wise_tax_detail",
-	)
-
-	tax_amount = 0
-	if item_wise_tax_detail and len(item_wise_tax_detail) > 0:
-		item_wise_tax_detail = json.loads(item_wise_tax_detail)
-		for key, value in item_wise_tax_detail.items():
-			if key == item_code:
-				tax_amount = value[1]
-				break
-
-	return tax_amount
diff --git a/erpnext/regional/saudi_arabia/__init__.py b/erpnext/regional/saudi_arabia/__init__.py
deleted file mode 100644
index e69de29..0000000
--- a/erpnext/regional/saudi_arabia/__init__.py
+++ /dev/null
diff --git a/erpnext/regional/saudi_arabia/setup.py b/erpnext/regional/saudi_arabia/setup.py
deleted file mode 100644
index 7f41c46..0000000
--- a/erpnext/regional/saudi_arabia/setup.py
+++ /dev/null
@@ -1,173 +0,0 @@
-# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
-# License: GNU General Public License v3. See license.txt
-
-import frappe
-from frappe.permissions import add_permission, update_permission_property
-from erpnext.regional.saudi_arabia.wizard.operations.setup_ksa_vat_setting import (
-	create_ksa_vat_setting,
-)
-from frappe.custom.doctype.custom_field.custom_field import create_custom_fields
-
-
-def setup(company=None, patch=True):
-	add_print_formats()
-	add_permissions()
-	make_custom_fields()
-
-
-def add_print_formats():
-	frappe.reload_doc("regional", "print_format", "detailed_tax_invoice", force=True)
-	frappe.reload_doc("regional", "print_format", "simplified_tax_invoice", force=True)
-	frappe.reload_doc("regional", "print_format", "tax_invoice", force=True)
-	frappe.reload_doc("regional", "print_format", "ksa_vat_invoice", force=True)
-	frappe.reload_doc("regional", "print_format", "ksa_pos_invoice", force=True)
-
-	for d in (
-		"Simplified Tax Invoice",
-		"Detailed Tax Invoice",
-		"Tax Invoice",
-		"KSA VAT Invoice",
-		"KSA POS Invoice",
-	):
-		frappe.db.set_value("Print Format", d, "disabled", 0)
-
-
-def add_permissions():
-	"""Add Permissions for KSA VAT Setting."""
-	add_permission("KSA VAT Setting", "All", 0)
-	for role in ("Accounts Manager", "Accounts User", "System Manager"):
-		add_permission("KSA VAT Setting", role, 0)
-		update_permission_property("KSA VAT Setting", role, 0, "write", 1)
-		update_permission_property("KSA VAT Setting", role, 0, "create", 1)
-
-	"""Enable KSA VAT Report"""
-	frappe.db.set_value("Report", "KSA VAT", "disabled", 0)
-
-
-def make_custom_fields():
-	"""Create Custom fields
-	- QR code Image file
-	- Company Name in Arabic
-	- Address in Arabic
-	"""
-	is_zero_rated = dict(
-		fieldname="is_zero_rated",
-		label="Is Zero Rated",
-		fieldtype="Check",
-		fetch_from="item_code.is_zero_rated",
-		insert_after="description",
-		print_hide=1,
-	)
-
-	is_exempt = dict(
-		fieldname="is_exempt",
-		label="Is Exempt",
-		fieldtype="Check",
-		fetch_from="item_code.is_exempt",
-		insert_after="is_zero_rated",
-		print_hide=1,
-	)
-
-	purchase_invoice_fields = [
-		dict(
-			fieldname="company_trn",
-			label="Company TRN",
-			fieldtype="Read Only",
-			insert_after="shipping_address",
-			fetch_from="company.tax_id",
-			print_hide=1,
-		),
-		dict(
-			fieldname="supplier_name_in_arabic",
-			label="Supplier Name in Arabic",
-			fieldtype="Read Only",
-			insert_after="supplier_name",
-			fetch_from="supplier.supplier_name_in_arabic",
-			print_hide=1,
-		),
-	]
-
-	sales_invoice_fields = [
-		dict(
-			fieldname="company_trn",
-			label="Company TRN",
-			fieldtype="Read Only",
-			insert_after="company_address",
-			fetch_from="company.tax_id",
-			print_hide=1,
-		),
-		dict(
-			fieldname="customer_name_in_arabic",
-			label="Customer Name in Arabic",
-			fieldtype="Read Only",
-			insert_after="customer_name",
-			fetch_from="customer.customer_name_in_arabic",
-			print_hide=1,
-		),
-		dict(
-			fieldname="ksa_einv_qr",
-			label="KSA E-Invoicing QR",
-			fieldtype="Attach Image",
-			read_only=1,
-			no_copy=1,
-			hidden=1,
-		),
-	]
-
-	custom_fields = {
-		"Item": [is_zero_rated, is_exempt],
-		"Customer": [
-			dict(
-				fieldname="customer_name_in_arabic",
-				label="Customer Name in Arabic",
-				fieldtype="Data",
-				insert_after="customer_name",
-			),
-		],
-		"Supplier": [
-			dict(
-				fieldname="supplier_name_in_arabic",
-				label="Supplier Name in Arabic",
-				fieldtype="Data",
-				insert_after="supplier_name",
-			),
-		],
-		"Purchase Invoice": purchase_invoice_fields,
-		"Purchase Order": purchase_invoice_fields,
-		"Purchase Receipt": purchase_invoice_fields,
-		"Sales Invoice": sales_invoice_fields,
-		"POS Invoice": sales_invoice_fields,
-		"Sales Order": sales_invoice_fields,
-		"Delivery Note": sales_invoice_fields,
-		"Sales Invoice Item": [is_zero_rated, is_exempt],
-		"POS Invoice Item": [is_zero_rated, is_exempt],
-		"Purchase Invoice Item": [is_zero_rated, is_exempt],
-		"Sales Order Item": [is_zero_rated, is_exempt],
-		"Delivery Note Item": [is_zero_rated, is_exempt],
-		"Quotation Item": [is_zero_rated, is_exempt],
-		"Purchase Order Item": [is_zero_rated, is_exempt],
-		"Purchase Receipt Item": [is_zero_rated, is_exempt],
-		"Supplier Quotation Item": [is_zero_rated, is_exempt],
-		"Address": [
-			dict(
-				fieldname="address_in_arabic",
-				label="Address in Arabic",
-				fieldtype="Data",
-				insert_after="address_line2",
-			)
-		],
-		"Company": [
-			dict(
-				fieldname="company_name_in_arabic",
-				label="Company Name In Arabic",
-				fieldtype="Data",
-				insert_after="company_name",
-			)
-		],
-	}
-
-	create_custom_fields(custom_fields, ignore_validate=True, update=True)
-
-
-def update_regional_tax_settings(country, company):
-	create_ksa_vat_setting(company)
diff --git a/erpnext/regional/saudi_arabia/utils.py b/erpnext/regional/saudi_arabia/utils.py
deleted file mode 100644
index cac5ec1..0000000
--- a/erpnext/regional/saudi_arabia/utils.py
+++ /dev/null
@@ -1,169 +0,0 @@
-import io
-import os
-from base64 import b64encode
-
-import frappe
-from frappe import _
-from frappe.custom.doctype.custom_field.custom_field import create_custom_fields
-from frappe.utils.data import add_to_date, get_time, getdate
-from pyqrcode import create as qr_create
-
-from erpnext import get_region
-
-
-def create_qr_code(doc, method=None):
-	region = get_region(doc.company)
-	if region not in ["Saudi Arabia"]:
-		return
-
-	# if QR Code field not present, create it. Invoices without QR are invalid as per law.
-	if not hasattr(doc, "ksa_einv_qr"):
-		create_custom_fields(
-			{
-				doc.doctype: [
-					dict(
-						fieldname="ksa_einv_qr",
-						label="KSA E-Invoicing QR",
-						fieldtype="Attach Image",
-						read_only=1,
-						no_copy=1,
-						hidden=1,
-					)
-				]
-			}
-		)
-
-	# Don't create QR Code if it already exists
-	qr_code = doc.get("ksa_einv_qr")
-	if qr_code and frappe.db.exists({"doctype": "File", "file_url": qr_code}):
-		return
-
-	meta = frappe.get_meta(doc.doctype)
-
-	if "ksa_einv_qr" in [d.fieldname for d in meta.get_image_fields()]:
-		"""TLV conversion for
-		1. Seller's Name
-		2. VAT Number
-		3. Time Stamp
-		4. Invoice Amount
-		5. VAT Amount
-		"""
-		tlv_array = []
-		# Sellers Name
-
-		seller_name = frappe.db.get_value("Company", doc.company, "company_name_in_arabic")
-
-		if not seller_name:
-			frappe.throw(_("Arabic name missing for {} in the company document").format(doc.company))
-
-		tag = bytes([1]).hex()
-		length = bytes([len(seller_name.encode("utf-8"))]).hex()
-		value = seller_name.encode("utf-8").hex()
-		tlv_array.append("".join([tag, length, value]))
-
-		# VAT Number
-		tax_id = frappe.db.get_value("Company", doc.company, "tax_id")
-		if not tax_id:
-			frappe.throw(_("Tax ID missing for {} in the company document").format(doc.company))
-
-		tag = bytes([2]).hex()
-		length = bytes([len(tax_id)]).hex()
-		value = tax_id.encode("utf-8").hex()
-		tlv_array.append("".join([tag, length, value]))
-
-		# Time Stamp
-		posting_date = getdate(doc.posting_date)
-		time = get_time(doc.posting_time)
-		seconds = time.hour * 60 * 60 + time.minute * 60 + time.second
-		time_stamp = add_to_date(posting_date, seconds=seconds)
-		time_stamp = time_stamp.strftime("%Y-%m-%dT%H:%M:%SZ")
-
-		tag = bytes([3]).hex()
-		length = bytes([len(time_stamp)]).hex()
-		value = time_stamp.encode("utf-8").hex()
-		tlv_array.append("".join([tag, length, value]))
-
-		# Invoice Amount
-		invoice_amount = str(doc.base_grand_total)
-		tag = bytes([4]).hex()
-		length = bytes([len(invoice_amount)]).hex()
-		value = invoice_amount.encode("utf-8").hex()
-		tlv_array.append("".join([tag, length, value]))
-
-		# VAT Amount
-		vat_amount = str(get_vat_amount(doc))
-
-		tag = bytes([5]).hex()
-		length = bytes([len(vat_amount)]).hex()
-		value = vat_amount.encode("utf-8").hex()
-		tlv_array.append("".join([tag, length, value]))
-
-		# Joining bytes into one
-		tlv_buff = "".join(tlv_array)
-
-		# base64 conversion for QR Code
-		base64_string = b64encode(bytes.fromhex(tlv_buff)).decode()
-
-		qr_image = io.BytesIO()
-		url = qr_create(base64_string, error="L")
-		url.png(qr_image, scale=2, quiet_zone=1)
-
-		name = frappe.generate_hash(doc.name, 5)
-
-		# making file
-		filename = f"QRCode-{name}.png".replace(os.path.sep, "__")
-		_file = frappe.get_doc(
-			{
-				"doctype": "File",
-				"file_name": filename,
-				"is_private": 0,
-				"content": qr_image.getvalue(),
-				"attached_to_doctype": doc.get("doctype"),
-				"attached_to_name": doc.get("name"),
-				"attached_to_field": "ksa_einv_qr",
-			}
-		)
-
-		_file.save()
-
-		# assigning to document
-		doc.db_set("ksa_einv_qr", _file.file_url)
-		doc.notify_update()
-
-
-def get_vat_amount(doc):
-	vat_settings = frappe.db.get_value("KSA VAT Setting", {"company": doc.company})
-	vat_accounts = []
-	vat_amount = 0
-
-	if vat_settings:
-		vat_settings_doc = frappe.get_cached_doc("KSA VAT Setting", vat_settings)
-
-		for row in vat_settings_doc.get("ksa_vat_sales_accounts"):
-			vat_accounts.append(row.account)
-
-	for tax in doc.get("taxes"):
-		if tax.account_head in vat_accounts:
-			vat_amount += tax.base_tax_amount
-
-	return vat_amount
-
-
-def delete_qr_code_file(doc, method=None):
-	region = get_region(doc.company)
-	if region not in ["Saudi Arabia"]:
-		return
-
-	if hasattr(doc, "ksa_einv_qr"):
-		if doc.get("ksa_einv_qr"):
-			file_doc = frappe.get_list("File", {"file_url": doc.get("ksa_einv_qr")})
-			if len(file_doc):
-				frappe.delete_doc("File", file_doc[0].name)
-
-
-def delete_vat_settings_for_company(doc, method=None):
-	if doc.country != "Saudi Arabia":
-		return
-
-	if frappe.db.exists("KSA VAT Setting", doc.name):
-		frappe.delete_doc("KSA VAT Setting", doc.name)
diff --git a/erpnext/regional/saudi_arabia/wizard/__init__.py b/erpnext/regional/saudi_arabia/wizard/__init__.py
deleted file mode 100644
index e69de29..0000000
--- a/erpnext/regional/saudi_arabia/wizard/__init__.py
+++ /dev/null
diff --git a/erpnext/regional/saudi_arabia/wizard/data/__init__.py b/erpnext/regional/saudi_arabia/wizard/data/__init__.py
deleted file mode 100644
index e69de29..0000000
--- a/erpnext/regional/saudi_arabia/wizard/data/__init__.py
+++ /dev/null
diff --git a/erpnext/regional/saudi_arabia/wizard/data/ksa_vat_settings.json b/erpnext/regional/saudi_arabia/wizard/data/ksa_vat_settings.json
deleted file mode 100644
index 60951a9..0000000
--- a/erpnext/regional/saudi_arabia/wizard/data/ksa_vat_settings.json
+++ /dev/null
@@ -1,47 +0,0 @@
-[
-    {
-        "type": "Sales Account",
-        "accounts": [
-            {
-                "title": "Standard rated Sales",
-                "item_tax_template": "KSA VAT 5%",
-                "account": "VAT 5%"
-            },
-            {
-                "title": "Zero rated domestic sales",
-                "item_tax_template": "KSA VAT Zero",
-                "account": "VAT Zero"
-            },
-            {
-                "title": "Exempted sales",
-                "item_tax_template": "KSA VAT Exempted",
-                "account": "VAT Exempted"
-            }
-        ]
-    },
-    {
-        "type": "Purchase Account",
-        "accounts": [
-            {
-                "title": "Standard rated domestic purchases",
-                "item_tax_template": "KSA VAT 5%",
-                "account": "VAT 5%"
-            },
-            {
-                "title": "Imports subject to VAT paid at customs",
-                "item_tax_template": "KSA Excise 50%",
-                "account": "Excise 50%"
-            },
-            {
-                "title": "Zero rated purchases",
-                "item_tax_template": "KSA VAT Zero",
-                "account": "VAT Zero"
-            },
-            {
-                "title": "Exempted purchases",
-                "item_tax_template": "KSA VAT Exempted",
-                "account": "VAT Exempted"
-            }
-        ]
-    }
-]
\ No newline at end of file
diff --git a/erpnext/regional/saudi_arabia/wizard/operations/__init__.py b/erpnext/regional/saudi_arabia/wizard/operations/__init__.py
deleted file mode 100644
index e69de29..0000000
--- a/erpnext/regional/saudi_arabia/wizard/operations/__init__.py
+++ /dev/null
diff --git a/erpnext/regional/saudi_arabia/wizard/operations/setup_ksa_vat_setting.py b/erpnext/regional/saudi_arabia/wizard/operations/setup_ksa_vat_setting.py
deleted file mode 100644
index 66d9df2..0000000
--- a/erpnext/regional/saudi_arabia/wizard/operations/setup_ksa_vat_setting.py
+++ /dev/null
@@ -1,46 +0,0 @@
-import json
-import os
-
-import frappe
-
-
-def create_ksa_vat_setting(company):
-	"""On creation of first company. Creates KSA VAT Setting"""
-
-	company = frappe.get_doc("Company", company)
-
-	file_path = os.path.join(os.path.dirname(__file__), "..", "data", "ksa_vat_settings.json")
-	with open(file_path, "r") as json_file:
-		account_data = json.load(json_file)
-
-	# Creating KSA VAT Setting
-	ksa_vat_setting = frappe.get_doc({"doctype": "KSA VAT Setting", "company": company.name})
-
-	for data in account_data:
-		if data["type"] == "Sales Account":
-			for row in data["accounts"]:
-				item_tax_template = row["item_tax_template"]
-				account = row["account"]
-				ksa_vat_setting.append(
-					"ksa_vat_sales_accounts",
-					{
-						"title": row["title"],
-						"item_tax_template": f"{item_tax_template} - {company.abbr}",
-						"account": f"{account} - {company.abbr}",
-					},
-				)
-
-		elif data["type"] == "Purchase Account":
-			for row in data["accounts"]:
-				item_tax_template = row["item_tax_template"]
-				account = row["account"]
-				ksa_vat_setting.append(
-					"ksa_vat_purchase_accounts",
-					{
-						"title": row["title"],
-						"item_tax_template": f"{item_tax_template} - {company.abbr}",
-						"account": f"{account} - {company.abbr}",
-					},
-				)
-
-	ksa_vat_setting.save()
diff --git a/erpnext/selling/doctype/customer/customer.json b/erpnext/selling/doctype/customer/customer.json
index 7482a33..c133cd3 100644
--- a/erpnext/selling/doctype/customer/customer.json
+++ b/erpnext/selling/doctype/customer/customer.json
@@ -24,10 +24,10 @@
   "account_manager",
   "image",
   "defaults_tab",
-  "default_price_list",
+  "default_currency",
   "default_bank_account",
   "column_break_14",
-  "default_currency",
+  "default_price_list",
   "internal_customer_section",
   "is_internal_customer",
   "represents_company",
@@ -568,11 +568,10 @@
    "link_fieldname": "party"
   }
  ],
- "modified": "2022-11-08 15:52:34.462657",
+ "modified": "2023-02-18 11:04:46.343527",
  "modified_by": "Administrator",
  "module": "Selling",
  "name": "Customer",
- "name_case": "Title Case",
  "naming_rule": "By \"Naming Series\" field",
  "owner": "Administrator",
  "permissions": [
diff --git a/erpnext/selling/doctype/industry_type/industry_type.json b/erpnext/selling/doctype/industry_type/industry_type.json
index 6c49f0f..3c8ab8e 100644
--- a/erpnext/selling/doctype/industry_type/industry_type.json
+++ b/erpnext/selling/doctype/industry_type/industry_type.json
@@ -1,123 +1,68 @@
 {
- "allow_copy": 0, 
- "allow_import": 1, 
- "allow_rename": 1, 
- "autoname": "field:industry", 
- "beta": 0, 
- "creation": "2012-03-27 14:36:09", 
- "custom": 0, 
- "docstatus": 0, 
- "doctype": "DocType", 
- "document_type": "Setup", 
- "editable_grid": 0, 
+ "actions": [],
+ "allow_import": 1,
+ "allow_rename": 1,
+ "autoname": "field:industry",
+ "creation": "2012-03-27 14:36:09",
+ "doctype": "DocType",
+ "document_type": "Setup",
+ "engine": "InnoDB",
+ "field_order": [
+  "industry"
+ ],
  "fields": [
   {
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "fieldname": "industry", 
-   "fieldtype": "Data", 
-   "hidden": 0, 
-   "ignore_user_permissions": 0, 
-   "ignore_xss_filter": 0, 
-   "in_filter": 0, 
-   "in_list_view": 0, 
-   "label": "Industry", 
-   "length": 0, 
-   "no_copy": 0, 
-   "oldfieldname": "industry", 
-   "oldfieldtype": "Data", 
-   "permlevel": 0, 
-   "print_hide": 0, 
-   "print_hide_if_no_value": 0, 
-   "read_only": 0, 
-   "report_hide": 0, 
-   "reqd": 1, 
-   "search_index": 0, 
-   "set_only_once": 0, 
-   "unique": 0
+   "fieldname": "industry",
+   "fieldtype": "Data",
+   "in_list_view": 1,
+   "label": "Industry",
+   "oldfieldname": "industry",
+   "oldfieldtype": "Data",
+   "reqd": 1,
+   "unique": 1
   }
- ], 
- "hide_heading": 0, 
- "hide_toolbar": 0, 
- "icon": "fa fa-flag", 
- "idx": 1, 
- "image_view": 0, 
- "in_create": 0, 
-
- "is_submittable": 0, 
- "issingle": 0, 
- "istable": 0, 
- "max_attachments": 0, 
- "modified": "2020-09-18 17:26:09.703215", 
- "modified_by": "Administrator", 
- "module": "Selling", 
- "name": "Industry Type", 
- "owner": "Administrator", 
+ ],
+ "icon": "fa fa-flag",
+ "idx": 1,
+ "links": [],
+ "modified": "2023-02-10 03:14:40.735763",
+ "modified_by": "Administrator",
+ "module": "Selling",
+ "name": "Industry Type",
+ "naming_rule": "By fieldname",
+ "owner": "Administrator",
  "permissions": [
   {
-   "amend": 0, 
-   "apply_user_permissions": 0, 
-   "cancel": 0, 
-   "create": 1, 
-   "delete": 0, 
-   "email": 1, 
-   "export": 0, 
-   "if_owner": 0, 
-   "import": 0, 
-   "permlevel": 0, 
-   "print": 1, 
-   "read": 1, 
-   "report": 1, 
-   "role": "Sales Manager", 
-   "set_user_permissions": 0, 
-   "share": 1, 
-   "submit": 0, 
+   "create": 1,
+   "email": 1,
+   "print": 1,
+   "read": 1,
+   "report": 1,
+   "role": "Sales Manager",
+   "share": 1,
    "write": 1
-  }, 
+  },
   {
-   "amend": 0, 
-   "apply_user_permissions": 0, 
-   "cancel": 0, 
-   "create": 0, 
-   "delete": 0, 
-   "email": 1, 
-   "export": 0, 
-   "if_owner": 0, 
-   "import": 0, 
-   "permlevel": 0, 
-   "print": 1, 
-   "read": 1, 
-   "report": 1, 
-   "role": "Sales User", 
-   "set_user_permissions": 0, 
-   "share": 0, 
-   "submit": 0, 
-   "write": 0
-  }, 
+   "email": 1,
+   "print": 1,
+   "read": 1,
+   "report": 1,
+   "role": "Sales User"
+  },
   {
-   "amend": 0, 
-   "apply_user_permissions": 0, 
-   "cancel": 0, 
-   "create": 1, 
-   "delete": 0, 
-   "email": 1, 
-   "export": 0, 
-   "if_owner": 0, 
-   "import": 0, 
-   "permlevel": 0, 
-   "print": 1, 
-   "read": 1, 
-   "report": 1, 
-   "role": "Sales Master Manager", 
-   "set_user_permissions": 0, 
-   "share": 1, 
-   "submit": 0, 
+   "create": 1,
+   "email": 1,
+   "print": 1,
+   "read": 1,
+   "report": 1,
+   "role": "Sales Master Manager",
+   "share": 1,
    "write": 1
   }
- ], 
- "quick_entry": 1, 
- "read_only": 0, 
- "read_only_onload": 0, 
- "track_seen": 0
+ ],
+ "quick_entry": 1,
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "states": [],
+ "translated_doctype": 1
 }
\ No newline at end of file
diff --git a/erpnext/selling/doctype/party_specific_item/party_specific_item.json b/erpnext/selling/doctype/party_specific_item/party_specific_item.json
index 32b5d47..a1f9902 100644
--- a/erpnext/selling/doctype/party_specific_item/party_specific_item.json
+++ b/erpnext/selling/doctype/party_specific_item/party_specific_item.json
@@ -1,5 +1,6 @@
 {
  "actions": [],
+ "allow_import": 1,
  "creation": "2021-08-27 19:28:07.559978",
  "doctype": "DocType",
  "editable_grid": 1,
@@ -51,7 +52,7 @@
  ],
  "index_web_pages_for_search": 1,
  "links": [],
- "modified": "2021-09-14 13:27:58.612334",
+ "modified": "2023-02-15 13:00:50.379713",
  "modified_by": "Administrator",
  "module": "Selling",
  "name": "Party Specific Item",
@@ -72,6 +73,7 @@
  ],
  "sort_field": "modified",
  "sort_order": "DESC",
+ "states": [],
  "title_field": "party",
  "track_changes": 1
 }
\ No newline at end of file
diff --git a/erpnext/selling/doctype/sales_partner_type/sales_partner_type.json b/erpnext/selling/doctype/sales_partner_type/sales_partner_type.json
index e7dd0d8..a9b500a 100644
--- a/erpnext/selling/doctype/sales_partner_type/sales_partner_type.json
+++ b/erpnext/selling/doctype/sales_partner_type/sales_partner_type.json
@@ -1,94 +1,47 @@
 {
- "allow_copy": 0, 
- "allow_guest_to_view": 0, 
- "allow_import": 0, 
- "allow_rename": 0, 
- "autoname": "field:sales_partner_type", 
- "beta": 0, 
- "creation": "2018-06-11 13:15:57.404716", 
- "custom": 0, 
- "docstatus": 0, 
- "doctype": "DocType", 
- "document_type": "", 
- "editable_grid": 1, 
- "engine": "InnoDB", 
+ "actions": [],
+ "autoname": "field:sales_partner_type",
+ "creation": "2018-06-11 13:15:57.404716",
+ "doctype": "DocType",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "field_order": [
+  "sales_partner_type"
+ ],
  "fields": [
   {
-   "allow_bulk_edit": 0, 
-   "allow_in_quick_entry": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "fieldname": "sales_partner_type", 
-   "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": "Sales Partner Type", 
-   "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
+   "fieldname": "sales_partner_type",
+   "fieldtype": "Data",
+   "in_list_view": 1,
+   "label": "Sales Partner Type",
+   "reqd": 1,
+   "unique": 1
   }
- ], 
- "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": "2018-06-11 13:45:13.554307", 
- "modified_by": "Administrator", 
- "module": "Selling", 
- "name": "Sales Partner Type", 
- "name_case": "", 
- "owner": "Administrator", 
+ ],
+ "links": [],
+ "modified": "2023-02-10 01:00:20.110800",
+ "modified_by": "Administrator",
+ "module": "Selling",
+ "name": "Sales Partner Type",
+ "naming_rule": "By fieldname",
+ "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, 
+   "create": 1,
+   "delete": 1,
+   "email": 1,
+   "export": 1,
+   "print": 1,
+   "read": 1,
+   "report": 1,
+   "role": "System Manager",
+   "share": 1,
    "write": 1
   }
- ], 
- "quick_entry": 1, 
- "read_only": 0, 
- "read_only_onload": 0, 
- "show_name_in_global_search": 0, 
- "sort_field": "modified", 
- "sort_order": "DESC", 
- "track_changes": 0, 
- "track_seen": 0
+ ],
+ "quick_entry": 1,
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "states": [],
+ "translated_doctype": 1
 }
\ No newline at end of file
diff --git a/erpnext/selling/report/item_wise_sales_history/item_wise_sales_history.py b/erpnext/selling/report/item_wise_sales_history/item_wise_sales_history.py
index 44c4d54..2624db3 100644
--- a/erpnext/selling/report/item_wise_sales_history/item_wise_sales_history.py
+++ b/erpnext/selling/report/item_wise_sales_history/item_wise_sales_history.py
@@ -216,7 +216,7 @@
 	)
 
 	if filters.get("item_group"):
-		query = query.where(db_so_item.item_group == frappe.db.escape(filters.item_group))
+		query = query.where(db_so_item.item_group == filters.item_group)
 
 	if filters.get("from_date"):
 		query = query.where(db_so.transaction_date >= filters.from_date)
@@ -225,7 +225,7 @@
 		query = query.where(db_so.transaction_date <= filters.to_date)
 
 	if filters.get("item_code"):
-		query = query.where(db_so_item.item_group == frappe.db.escape(filters.item_code))
+		query = query.where(db_so_item.item_code == filters.item_code)
 
 	if filters.get("customer"):
 		query = query.where(db_so.customer == filters.customer)
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 63d339a..2969123 100644
--- a/erpnext/selling/report/sales_order_analysis/sales_order_analysis.py
+++ b/erpnext/selling/report/sales_order_analysis/sales_order_analysis.py
@@ -175,7 +175,9 @@
 				# update existing entry
 				so_row = sales_order_map[so_name]
 				so_row["required_date"] = max(getdate(so_row["delivery_date"]), getdate(row["delivery_date"]))
-				so_row["delay"] = min(so_row["delay"], row["delay"])
+				so_row["delay"] = (
+					min(so_row["delay"], row["delay"]) if row["delay"] and so_row["delay"] else so_row["delay"]
+				)
 
 				# sum numeric columns
 				fields = [
diff --git a/erpnext/selling/sales_common.js b/erpnext/selling/sales_common.js
index 8ff01f5..5ce6e9c 100644
--- a/erpnext/selling/sales_common.js
+++ b/erpnext/selling/sales_common.js
@@ -418,8 +418,6 @@
 			callback: function(r) {
 				if(r.message) {
 					frappe.model.set_value(doc.doctype, doc.name, 'batch_no', r.message);
-				} else {
-				    frappe.model.set_value(doc.doctype, doc.name, 'batch_no', r.message);
 				}
 			}
 		});
diff --git a/erpnext/setup/doctype/designation/designation.json b/erpnext/setup/doctype/designation/designation.json
index 2cbbb04..a5b2ac9 100644
--- a/erpnext/setup/doctype/designation/designation.json
+++ b/erpnext/setup/doctype/designation/designation.json
@@ -31,7 +31,7 @@
  "icon": "fa fa-bookmark",
  "idx": 1,
  "links": [],
- "modified": "2022-06-28 17:10:26.853753",
+ "modified": "2023-02-10 01:53:41.319386",
  "modified_by": "Administrator",
  "module": "Setup",
  "name": "Designation",
@@ -58,5 +58,6 @@
  "show_name_in_global_search": 1,
  "sort_field": "modified",
  "sort_order": "ASC",
- "states": []
+ "states": [],
+ "translated_doctype": 1
 }
\ No newline at end of file
diff --git a/erpnext/setup/doctype/employee/employee.py b/erpnext/setup/doctype/employee/employee.py
index facefa3..ece5a7d 100755
--- a/erpnext/setup/doctype/employee/employee.py
+++ b/erpnext/setup/doctype/employee/employee.py
@@ -8,7 +8,6 @@
 	get_doc_permissions,
 	has_permission,
 	remove_user_permission,
-	set_user_permission_if_allowed,
 )
 from frappe.utils import cstr, getdate, today, validate_email_address
 from frappe.utils.nestedset import NestedSet
@@ -96,7 +95,7 @@
 			return
 
 		add_user_permission("Employee", self.name, self.user_id)
-		set_user_permission_if_allowed("Company", self.company, self.user_id)
+		add_user_permission("Company", self.company, self.user_id)
 
 	def update_user(self):
 		# add employee role if missing
diff --git a/erpnext/setup/doctype/transaction_deletion_record/transaction_deletion_record.py b/erpnext/setup/doctype/transaction_deletion_record/transaction_deletion_record.py
index 4256a7d..481a3a5 100644
--- a/erpnext/setup/doctype/transaction_deletion_record/transaction_deletion_record.py
+++ b/erpnext/setup/doctype/transaction_deletion_record/transaction_deletion_record.py
@@ -3,13 +3,17 @@
 
 
 import frappe
-from frappe import _
+from frappe import _, qb
 from frappe.desk.notifications import clear_notifications
 from frappe.model.document import Document
-from frappe.utils import cint
+from frappe.utils import cint, create_batch
 
 
 class TransactionDeletionRecord(Document):
+	def __init__(self, *args, **kwargs):
+		super(TransactionDeletionRecord, self).__init__(*args, **kwargs)
+		self.batch_size = 5000
+
 	def validate(self):
 		frappe.only_for("System Manager")
 		self.validate_doctypes_to_be_ignored()
@@ -155,8 +159,9 @@
 			"DocField", filters={"fieldtype": "Table", "parent": doctype}, pluck="options"
 		)
 
-		for table in child_tables:
-			frappe.db.delete(table, {"parent": ["in", parent_docs_to_be_deleted]})
+		for batch in create_batch(parent_docs_to_be_deleted, self.batch_size):
+			for table in child_tables:
+				frappe.db.delete(table, {"parent": ["in", batch]})
 
 	def delete_docs_linked_with_specified_company(self, doctype, company_fieldname):
 		frappe.db.delete(doctype, {company_fieldname: self.company})
@@ -181,13 +186,16 @@
 		frappe.db.sql("""update `tabSeries` set current = %s where name=%s""", (last, prefix))
 
 	def delete_version_log(self, doctype, company_fieldname):
-		frappe.db.sql(
-			"""delete from `tabVersion` where ref_doctype=%s and docname in
-			(select name from `tab{0}` where `{1}`=%s)""".format(
-				doctype, company_fieldname
-			),
-			(doctype, self.company),
-		)
+		dt = qb.DocType(doctype)
+		names = qb.from_(dt).select(dt.name).where(dt[company_fieldname] == self.company).run(as_list=1)
+		names = [x[0] for x in names]
+
+		if names:
+			versions = qb.DocType("Version")
+			for batch in create_batch(names, self.batch_size):
+				qb.from_(versions).delete().where(
+					(versions.ref_doctype == doctype) & (versions.docname.isin(batch))
+				).run()
 
 	def delete_communications(self, doctype, company_fieldname):
 		reference_docs = frappe.get_all(doctype, filters={company_fieldname: self.company})
@@ -199,7 +207,8 @@
 		)
 		communication_names = [c.name for c in communications]
 
-		frappe.delete_doc("Communication", communication_names, ignore_permissions=True)
+		for batch in create_batch(communication_names, self.batch_size):
+			frappe.delete_doc("Communication", batch, ignore_permissions=True)
 
 
 @frappe.whitelist()
diff --git a/erpnext/setup/setup_wizard/data/country_wise_tax.json b/erpnext/setup/setup_wizard/data/country_wise_tax.json
index 45e39c5..5750914 100644
--- a/erpnext/setup/setup_wizard/data/country_wise_tax.json
+++ b/erpnext/setup/setup_wizard/data/country_wise_tax.json
@@ -4015,34 +4015,6 @@
 			"tax_rate": 18.00
 		}
 	},
-
-	"Saudi Arabia": {
-		"KSA VAT 15%": {
-			"account_name": "VAT 15%",
-			"tax_rate": 15.00
-		},
-		"KSA VAT 5%": {
-			"account_name": "VAT 5%",
-			"tax_rate": 5.00
-		},
-		"KSA VAT Zero": {
-			"account_name": "VAT Zero",
-			"tax_rate": 0.00
-		},
-		"KSA VAT Exempted": {
-			"account_name": "VAT Exempted",
-			"tax_rate": 0.00
-		},
-		"KSA Excise 50%": {
-			"account_name": "Excise 50%",
-			"tax_rate": 50.00
-		},
-		"KSA Excise 100%": {
-			"account_name": "Excise 100%",
-			"tax_rate": 100.00
-		}
-	},
-
 	"Serbia": {
 		"Serbia Tax": {
 			"account_name": "VAT",
diff --git a/erpnext/setup/setup_wizard/data/designation.txt b/erpnext/setup/setup_wizard/data/designation.txt
new file mode 100644
index 0000000..4c6d7bd
--- /dev/null
+++ b/erpnext/setup/setup_wizard/data/designation.txt
@@ -0,0 +1,31 @@
+Accountant
+Administrative Assistant
+Administrative Officer
+Analyst
+Associate
+Business Analyst
+Business Development Manager
+Consultant
+Chief Executive Officer
+Chief Financial Officer
+Chief Operating Officer
+Chief Technology Officer
+Customer Service Representative
+Designer
+Engineer
+Executive Assistant
+Finance Manager
+HR Manager
+Head of Marketing and Sales
+Manager
+Managing Director
+Marketing Manager
+Marketing Specialist
+President
+Product Manager
+Project Manager
+Researcher
+Sales Representative
+Secretary
+Software Developer
+Vice President
diff --git a/erpnext/setup/setup_wizard/data/industry_type.py b/erpnext/setup/setup_wizard/data/industry_type.py
deleted file mode 100644
index 0bc3f32..0000000
--- a/erpnext/setup/setup_wizard/data/industry_type.py
+++ /dev/null
@@ -1,57 +0,0 @@
-from frappe import _
-
-
-def get_industry_types():
-	return [
-		_("Accounting"),
-		_("Advertising"),
-		_("Aerospace"),
-		_("Agriculture"),
-		_("Airline"),
-		_("Apparel & Accessories"),
-		_("Automotive"),
-		_("Banking"),
-		_("Biotechnology"),
-		_("Broadcasting"),
-		_("Brokerage"),
-		_("Chemical"),
-		_("Computer"),
-		_("Consulting"),
-		_("Consumer Products"),
-		_("Cosmetics"),
-		_("Defense"),
-		_("Department Stores"),
-		_("Education"),
-		_("Electronics"),
-		_("Energy"),
-		_("Entertainment & Leisure"),
-		_("Executive Search"),
-		_("Financial Services"),
-		_("Food, Beverage & Tobacco"),
-		_("Grocery"),
-		_("Health Care"),
-		_("Internet Publishing"),
-		_("Investment Banking"),
-		_("Legal"),
-		_("Manufacturing"),
-		_("Motion Picture & Video"),
-		_("Music"),
-		_("Newspaper Publishers"),
-		_("Online Auctions"),
-		_("Pension Funds"),
-		_("Pharmaceuticals"),
-		_("Private Equity"),
-		_("Publishing"),
-		_("Real Estate"),
-		_("Retail & Wholesale"),
-		_("Securities & Commodity Exchanges"),
-		_("Service"),
-		_("Soap & Detergent"),
-		_("Software"),
-		_("Sports"),
-		_("Technology"),
-		_("Telecommunications"),
-		_("Television"),
-		_("Transportation"),
-		_("Venture Capital"),
-	]
diff --git a/erpnext/setup/setup_wizard/data/industry_type.txt b/erpnext/setup/setup_wizard/data/industry_type.txt
new file mode 100644
index 0000000..eadc689
--- /dev/null
+++ b/erpnext/setup/setup_wizard/data/industry_type.txt
@@ -0,0 +1,51 @@
+Accounting
+Advertising
+Aerospace
+Agriculture
+Airline
+Apparel & Accessories
+Automotive
+Banking
+Biotechnology
+Broadcasting
+Brokerage
+Chemical
+Computer
+Consulting
+Consumer Products
+Cosmetics
+Defense
+Department Stores
+Education
+Electronics
+Energy
+Entertainment & Leisure
+Executive Search
+Financial Services
+Food, Beverage & Tobacco
+Grocery
+Health Care
+Internet Publishing
+Investment Banking
+Legal
+Manufacturing
+Motion Picture & Video
+Music
+Newspaper Publishers
+Online Auctions
+Pension Funds
+Pharmaceuticals
+Private Equity
+Publishing
+Real Estate
+Retail & Wholesale
+Securities & Commodity Exchanges
+Service
+Soap & Detergent
+Software
+Sports
+Technology
+Telecommunications
+Television
+Transportation
+Venture Capital
diff --git a/erpnext/setup/setup_wizard/data/lead_source.txt b/erpnext/setup/setup_wizard/data/lead_source.txt
new file mode 100644
index 0000000..00ca180
--- /dev/null
+++ b/erpnext/setup/setup_wizard/data/lead_source.txt
@@ -0,0 +1,10 @@
+Existing Customer
+Reference
+Advertisement
+Cold Calling
+Exhibition
+Supplier Reference
+Mass Mailing
+Customer's Vendor
+Campaign
+Walk In
diff --git a/erpnext/setup/setup_wizard/data/sales_partner_type.txt b/erpnext/setup/setup_wizard/data/sales_partner_type.txt
new file mode 100644
index 0000000..68e9b9a
--- /dev/null
+++ b/erpnext/setup/setup_wizard/data/sales_partner_type.txt
@@ -0,0 +1,7 @@
+Channel Partner
+Distributor
+Dealer
+Agent
+Retailer
+Implementation Partner
+Reseller
diff --git a/erpnext/setup/setup_wizard/data/sales_stage.txt b/erpnext/setup/setup_wizard/data/sales_stage.txt
new file mode 100644
index 0000000..2808ce7
--- /dev/null
+++ b/erpnext/setup/setup_wizard/data/sales_stage.txt
@@ -0,0 +1,8 @@
+Prospecting
+Qualification
+Needs Analysis
+Value Proposition
+Identifying Decision Makers
+Perception Analysis
+Proposal/Price Quote
+Negotiation/Review
diff --git a/erpnext/setup/setup_wizard/operations/install_fixtures.py b/erpnext/setup/setup_wizard/operations/install_fixtures.py
index 1f8c0d6..6bc1771 100644
--- a/erpnext/setup/setup_wizard/operations/install_fixtures.py
+++ b/erpnext/setup/setup_wizard/operations/install_fixtures.py
@@ -4,6 +4,7 @@
 
 import json
 import os
+from pathlib import Path
 
 import frappe
 from frappe import _
@@ -16,28 +17,10 @@
 from erpnext.accounts.doctype.account.account import RootNotEditable
 from erpnext.regional.address_template.setup import set_up_address_templates
 
-default_lead_sources = [
-	"Existing Customer",
-	"Reference",
-	"Advertisement",
-	"Cold Calling",
-	"Exhibition",
-	"Supplier Reference",
-	"Mass Mailing",
-	"Customer's Vendor",
-	"Campaign",
-	"Walk In",
-]
 
-default_sales_partner_type = [
-	"Channel Partner",
-	"Distributor",
-	"Dealer",
-	"Agent",
-	"Retailer",
-	"Implementation Partner",
-	"Reseller",
-]
+def read_lines(filename: str) -> list[str]:
+	"""Return a list of lines from a file in the data directory."""
+	return (Path(__file__).parent.parent / "data" / filename).read_text().splitlines()
 
 
 def install(country=None):
@@ -85,7 +68,11 @@
 		# Stock Entry Type
 		{"doctype": "Stock Entry Type", "name": "Material Issue", "purpose": "Material Issue"},
 		{"doctype": "Stock Entry Type", "name": "Material Receipt", "purpose": "Material Receipt"},
-		{"doctype": "Stock Entry Type", "name": "Material Transfer", "purpose": "Material Transfer"},
+		{
+			"doctype": "Stock Entry Type",
+			"name": "Material Transfer",
+			"purpose": "Material Transfer",
+		},
 		{"doctype": "Stock Entry Type", "name": "Manufacture", "purpose": "Manufacture"},
 		{"doctype": "Stock Entry Type", "name": "Repack", "purpose": "Repack"},
 		{
@@ -103,22 +90,6 @@
 			"name": "Material Consumption for Manufacture",
 			"purpose": "Material Consumption for Manufacture",
 		},
-		# Designation
-		{"doctype": "Designation", "designation_name": _("CEO")},
-		{"doctype": "Designation", "designation_name": _("Manager")},
-		{"doctype": "Designation", "designation_name": _("Analyst")},
-		{"doctype": "Designation", "designation_name": _("Engineer")},
-		{"doctype": "Designation", "designation_name": _("Accountant")},
-		{"doctype": "Designation", "designation_name": _("Secretary")},
-		{"doctype": "Designation", "designation_name": _("Associate")},
-		{"doctype": "Designation", "designation_name": _("Administrative Officer")},
-		{"doctype": "Designation", "designation_name": _("Business Development Manager")},
-		{"doctype": "Designation", "designation_name": _("HR Manager")},
-		{"doctype": "Designation", "designation_name": _("Project Manager")},
-		{"doctype": "Designation", "designation_name": _("Head of Marketing and Sales")},
-		{"doctype": "Designation", "designation_name": _("Software Developer")},
-		{"doctype": "Designation", "designation_name": _("Designer")},
-		{"doctype": "Designation", "designation_name": _("Researcher")},
 		# territory: with two default territories, one for home country and one named Rest of the World
 		{
 			"doctype": "Territory",
@@ -291,28 +262,18 @@
 		{"doctype": "Market Segment", "market_segment": _("Lower Income")},
 		{"doctype": "Market Segment", "market_segment": _("Middle Income")},
 		{"doctype": "Market Segment", "market_segment": _("Upper Income")},
-		# Sales Stages
-		{"doctype": "Sales Stage", "stage_name": _("Prospecting")},
-		{"doctype": "Sales Stage", "stage_name": _("Qualification")},
-		{"doctype": "Sales Stage", "stage_name": _("Needs Analysis")},
-		{"doctype": "Sales Stage", "stage_name": _("Value Proposition")},
-		{"doctype": "Sales Stage", "stage_name": _("Identifying Decision Makers")},
-		{"doctype": "Sales Stage", "stage_name": _("Perception Analysis")},
-		{"doctype": "Sales Stage", "stage_name": _("Proposal/Price Quote")},
-		{"doctype": "Sales Stage", "stage_name": _("Negotiation/Review")},
 		# Warehouse Type
 		{"doctype": "Warehouse Type", "name": "Transit"},
 	]
 
-	from erpnext.setup.setup_wizard.data.industry_type import get_industry_types
-
-	records += [{"doctype": "Industry Type", "industry": d} for d in get_industry_types()]
-	# records += [{"doctype":"Operation", "operation": d} for d in get_operations()]
-	records += [{"doctype": "Lead Source", "source_name": _(d)} for d in default_lead_sources]
-
-	records += [
-		{"doctype": "Sales Partner Type", "sales_partner_type": _(d)} for d in default_sales_partner_type
-	]
+	for doctype, title_field, filename in (
+		("Designation", "designation_name", "designation.txt"),
+		("Sales Stage", "stage_name", "sales_stage.txt"),
+		("Industry Type", "industry", "industry_type.txt"),
+		("Lead Source", "source_name", "lead_source.txt"),
+		("Sales Partner Type", "sales_partner_type", "sales_partner_type.txt"),
+	):
+		records += [{"doctype": doctype, title_field: title} for title in read_lines(filename)]
 
 	base_path = frappe.get_app_path("erpnext", "stock", "doctype")
 	response = frappe.read_file(
@@ -397,7 +358,8 @@
 			frappe.get_doc({"doctype": "UOM Category", "category_name": _(d.get("category"))}).db_insert()
 
 		if not frappe.db.exists(
-			"UOM Conversion Factor", {"from_uom": _(d.get("from_uom")), "to_uom": _(d.get("to_uom"))}
+			"UOM Conversion Factor",
+			{"from_uom": _(d.get("from_uom")), "to_uom": _(d.get("to_uom"))},
 		):
 			frappe.get_doc(
 				{
@@ -535,7 +497,8 @@
 
 	company_name = args.get("company_name")
 	bank_account_group = frappe.db.get_value(
-		"Account", {"account_type": "Bank", "is_group": 1, "root_type": "Asset", "company": company_name}
+		"Account",
+		{"account_type": "Bank", "is_group": 1, "root_type": "Asset", "company": company_name},
 	)
 	if bank_account_group:
 		bank_account = frappe.get_doc(
diff --git a/erpnext/stock/doctype/delivery_note/delivery_note.js b/erpnext/stock/doctype/delivery_note/delivery_note.js
index ea3cf19..ae56645 100644
--- a/erpnext/stock/doctype/delivery_note/delivery_note.js
+++ b/erpnext/stock/doctype/delivery_note/delivery_note.js
@@ -97,12 +97,12 @@
 		}
 
 		if (frm.doc.docstatus == 1 && !frm.doc.inter_company_reference) {
-			let internal = me.frm.doc.is_internal_customer;
+			let internal = frm.doc.is_internal_customer;
 			if (internal) {
-				let button_label = (me.frm.doc.company === me.frm.doc.represents_company) ? "Internal Purchase Receipt" :
+				let button_label = (frm.doc.company === frm.doc.represents_company) ? "Internal Purchase Receipt" :
 					"Inter Company Purchase Receipt";
 
-				me.frm.add_custom_button(button_label, function() {
+				frm.add_custom_button(__(button_label), function() {
 					frappe.model.open_mapped_doc({
 						method: 'erpnext.stock.doctype.delivery_note.delivery_note.make_inter_company_purchase_receipt',
 						frm: frm,
diff --git a/erpnext/stock/doctype/delivery_note/delivery_note.json b/erpnext/stock/doctype/delivery_note/delivery_note.json
index 165a56b..0c1f820 100644
--- a/erpnext/stock/doctype/delivery_note/delivery_note.json
+++ b/erpnext/stock/doctype/delivery_note/delivery_note.json
@@ -521,6 +521,7 @@
    "allow_bulk_edit": 1,
    "fieldname": "items",
    "fieldtype": "Table",
+   "label": "Delivery Note Item",
    "oldfieldname": "delivery_note_details",
    "oldfieldtype": "Table",
    "options": "Delivery Note Item",
@@ -666,6 +667,7 @@
   {
    "fieldname": "taxes",
    "fieldtype": "Table",
+   "label": "Sales Taxes and Charges",
    "oldfieldname": "other_charges",
    "oldfieldtype": "Table",
    "options": "Sales Taxes and Charges"
@@ -1401,7 +1403,7 @@
  "idx": 146,
  "is_submittable": 1,
  "links": [],
- "modified": "2022-12-12 18:38:53.067799",
+ "modified": "2023-02-14 04:45:44.179670",
  "modified_by": "Administrator",
  "module": "Stock",
  "name": "Delivery Note",
diff --git a/erpnext/stock/doctype/delivery_note/delivery_note_list.js b/erpnext/stock/doctype/delivery_note/delivery_note_list.js
index 9e6f3bc..6ff3ed3 100644
--- a/erpnext/stock/doctype/delivery_note/delivery_note_list.js
+++ b/erpnext/stock/doctype/delivery_note/delivery_note_list.js
@@ -14,7 +14,7 @@
 			return [__("Completed"), "green", "per_billed,=,100"];
 		}
 	},
-	onload: function (listview) {
+	onload: function (doclist) {
 		const action = () => {
 			const selected_docs = doclist.get_checked_items();
 			const docnames = doclist.get_checked_items(true);
@@ -56,14 +56,14 @@
 
 		// doclist.page.add_actions_menu_item(__('Create Delivery Trip'), action, false);
 
-		listview.page.add_action_item(__('Create Delivery Trip'), action);
+		doclist.page.add_action_item(__('Create Delivery Trip'), action);
 
-		listview.page.add_action_item(__("Sales Invoice"), ()=>{
-			erpnext.bulk_transaction_processing.create(listview, "Delivery Note", "Sales Invoice");
+		doclist.page.add_action_item(__("Sales Invoice"), ()=>{
+			erpnext.bulk_transaction_processing.create(doclist, "Delivery Note", "Sales Invoice");
 		});
 
-		listview.page.add_action_item(__("Packaging Slip From Delivery Note"), ()=>{
-			erpnext.bulk_transaction_processing.create(listview, "Delivery Note", "Packing Slip");
+		doclist.page.add_action_item(__("Packaging Slip From Delivery Note"), ()=>{
+			erpnext.bulk_transaction_processing.create(doclist, "Delivery Note", "Packing Slip");
 		});
 	}
 };
diff --git a/erpnext/stock/doctype/item/item.json b/erpnext/stock/doctype/item/item.json
index 629e50e..34adbeb 100644
--- a/erpnext/stock/doctype/item/item.json
+++ b/erpnext/stock/doctype/item/item.json
@@ -706,7 +706,7 @@
    "depends_on": "enable_deferred_expense",
    "fieldname": "no_of_months_exp",
    "fieldtype": "Int",
-   "label": "No of Months"
+   "label": "No of Months (Expense)"
   },
   {
    "collapsible": 1,
@@ -911,7 +911,7 @@
  "index_web_pages_for_search": 1,
  "links": [],
  "make_attachments_public": 1,
- "modified": "2023-01-07 22:45:00.341745",
+ "modified": "2023-02-14 04:48:26.343620",
  "modified_by": "Administrator",
  "module": "Stock",
  "name": "Item",
diff --git a/erpnext/stock/doctype/item/item.py b/erpnext/stock/doctype/item/item.py
index 686e6cb..c06700a 100644
--- a/erpnext/stock/doctype/item/item.py
+++ b/erpnext/stock/doctype/item/item.py
@@ -358,7 +358,7 @@
 					check_list.append(d.item_tax_template)
 
 	def validate_barcode(self):
-		from stdnum import ean
+		import barcodenumber
 
 		if len(self.barcodes) > 0:
 			for item_barcode in self.barcodes:
@@ -376,19 +376,16 @@
 					item_barcode.barcode_type = (
 						"" if item_barcode.barcode_type not in options else item_barcode.barcode_type
 					)
-					if item_barcode.barcode_type and item_barcode.barcode_type.upper() in (
-						"EAN",
-						"UPC-A",
-						"EAN-13",
-						"EAN-8",
-					):
-						if not ean.is_valid(item_barcode.barcode):
-							frappe.throw(
-								_("Barcode {0} is not a valid {1} code").format(
-									item_barcode.barcode, item_barcode.barcode_type
-								),
-								InvalidBarcode,
-							)
+					if item_barcode.barcode_type:
+						barcode_type = convert_erpnext_to_barcodenumber(item_barcode.barcode_type.upper())
+						if barcode_type in barcodenumber.barcodes():
+							if not barcodenumber.check_code(barcode_type, item_barcode.barcode):
+								frappe.throw(
+									_("Barcode {0} is not a valid {1} code").format(
+										item_barcode.barcode, item_barcode.barcode_type
+									),
+									InvalidBarcode,
+								)
 
 	def validate_warehouse_for_reorder(self):
 		"""Validate Reorder level table for duplicate and conditional mandatory"""
@@ -985,6 +982,22 @@
 				)
 
 
+def convert_erpnext_to_barcodenumber(erpnext_number):
+	convert = {
+		"UPC-A": "UPCA",
+		"CODE-39": "CODE39",
+		"EAN": "EAN13",
+		"EAN-12": "EAN",
+		"EAN-8": "EAN8",
+		"ISBN-10": "ISBN10",
+		"ISBN-13": "ISBN13",
+	}
+	if erpnext_number in convert:
+		return convert[erpnext_number]
+	else:
+		return erpnext_number
+
+
 def make_item_price(item, price_list_name, item_price):
 	frappe.get_doc(
 		{
diff --git a/erpnext/stock/doctype/item/test_item.py b/erpnext/stock/doctype/item/test_item.py
index 53f6b7f..67ed90d 100644
--- a/erpnext/stock/doctype/item/test_item.py
+++ b/erpnext/stock/doctype/item/test_item.py
@@ -579,6 +579,19 @@
 			{
 				"barcode": "ARBITRARY_TEXT",
 			},
+			{"barcode": "72527273070", "barcode_type": "UPC-A"},
+			{"barcode": "123456", "barcode_type": "CODE-39"},
+			{"barcode": "401268452363", "barcode_type": "EAN-12"},
+			{"barcode": "90311017", "barcode_type": "EAN-8"},
+			{"barcode": "0123456789012", "barcode_type": "GS1"},
+			{"barcode": "2211564566668", "barcode_type": "GTIN"},
+			{"barcode": "0256480249", "barcode_type": "ISBN"},
+			{"barcode": "0192552570", "barcode_type": "ISBN-10"},
+			{"barcode": "9781234567897", "barcode_type": "ISBN-13"},
+			{"barcode": "9771234567898", "barcode_type": "ISSN"},
+			{"barcode": "4581171967072", "barcode_type": "JAN"},
+			{"barcode": "12345678", "barcode_type": "PZN"},
+			{"barcode": "725272730706", "barcode_type": "UPC"},
 		]
 		create_item(item_code)
 		for barcode_properties in barcode_properties_list:
diff --git a/erpnext/stock/doctype/item_barcode/item_barcode.json b/erpnext/stock/doctype/item_barcode/item_barcode.json
index bda1218..d9a8347 100644
--- a/erpnext/stock/doctype/item_barcode/item_barcode.json
+++ b/erpnext/stock/doctype/item_barcode/item_barcode.json
@@ -25,7 +25,7 @@
    "fieldtype": "Select",
    "in_list_view": 1,
    "label": "Barcode Type",
-   "options": "\nEAN\nUPC-A"
+   "options": "\nEAN\nUPC-A\nCODE-39\nEAN-12\nEAN-8\nGS1\nGTIN\nISBN\nISBN-10\nISBN-13\nISSN\nJAN\nPZN\nUPC"
   },
   {
    "fieldname": "uom",
diff --git a/erpnext/stock/doctype/item_price/test_records.json b/erpnext/stock/doctype/item_price/test_records.json
index 0a3d7e8..afe5ad6 100644
--- a/erpnext/stock/doctype/item_price/test_records.json
+++ b/erpnext/stock/doctype/item_price/test_records.json
@@ -38,5 +38,19 @@
   "price_list_rate": 1000,
   "valid_from": "2017-04-10",
   "valid_upto": "2017-04-17"
+ },
+ {
+  "doctype": "Item Price",
+  "item_code": "_Test Item",
+  "price_list": "_Test Buying Price List",
+  "price_list_rate": 100,
+  "supplier": "_Test Supplier"
+ },
+ {
+  "doctype": "Item Price",
+  "item_code": "_Test Item",
+  "price_list": "_Test Selling Price List",
+  "price_list_rate": 200,
+  "customer": "_Test Customer"
  }
 ]
diff --git a/erpnext/stock/doctype/landed_cost_voucher/landed_cost_voucher.py b/erpnext/stock/doctype/landed_cost_voucher/landed_cost_voucher.py
index b3af309..111a0861 100644
--- a/erpnext/stock/doctype/landed_cost_voucher/landed_cost_voucher.py
+++ b/erpnext/stock/doctype/landed_cost_voucher/landed_cost_voucher.py
@@ -55,7 +55,6 @@
 			self.get_items_from_purchase_receipts()
 
 		self.set_applicable_charges_on_item()
-		self.validate_applicable_charges_for_item()
 
 	def check_mandatory(self):
 		if not self.get("purchase_receipts"):
@@ -115,6 +114,13 @@
 				total_item_cost += item.get(based_on_field)
 
 			for item in self.get("items"):
+				if not total_item_cost and not item.get(based_on_field):
+					frappe.throw(
+						_(
+							"It's not possible to distribute charges equally when total amount is zero, please set 'Distribute Charges Based On' as 'Quantity'"
+						)
+					)
+
 				item.applicable_charges = flt(
 					flt(item.get(based_on_field)) * (flt(self.total_taxes_and_charges) / flt(total_item_cost)),
 					item.precision("applicable_charges"),
@@ -162,6 +168,7 @@
 			)
 
 	def on_submit(self):
+		self.validate_applicable_charges_for_item()
 		self.update_landed_cost()
 
 	def on_cancel(self):
diff --git a/erpnext/stock/doctype/landed_cost_voucher/test_landed_cost_voucher.py b/erpnext/stock/doctype/landed_cost_voucher/test_landed_cost_voucher.py
index 979b5c4..00fa168 100644
--- a/erpnext/stock/doctype/landed_cost_voucher/test_landed_cost_voucher.py
+++ b/erpnext/stock/doctype/landed_cost_voucher/test_landed_cost_voucher.py
@@ -175,6 +175,59 @@
 		)
 		self.assertEqual(last_sle_after_landed_cost.stock_value - last_sle.stock_value, 50.0)
 
+	def test_landed_cost_voucher_for_zero_purchase_rate(self):
+		"Test impact of LCV on future stock balances."
+		from erpnext.stock.doctype.item.test_item import make_item
+
+		item = make_item("LCV Stock Item", {"is_stock_item": 1})
+		warehouse = "Stores - _TC"
+
+		pr = make_purchase_receipt(
+			item_code=item.name,
+			warehouse=warehouse,
+			qty=10,
+			rate=0,
+			posting_date=add_days(frappe.utils.nowdate(), -2),
+		)
+
+		self.assertEqual(
+			frappe.db.get_value(
+				"Stock Ledger Entry",
+				{"voucher_type": "Purchase Receipt", "voucher_no": pr.name, "is_cancelled": 0},
+				"stock_value_difference",
+			),
+			0,
+		)
+
+		lcv = make_landed_cost_voucher(
+			company=pr.company,
+			receipt_document_type="Purchase Receipt",
+			receipt_document=pr.name,
+			charges=100,
+			distribute_charges_based_on="Distribute Manually",
+			do_not_save=True,
+		)
+
+		lcv.get_items_from_purchase_receipts()
+		lcv.items[0].applicable_charges = 100
+		lcv.save()
+		lcv.submit()
+
+		self.assertTrue(
+			frappe.db.exists(
+				"Stock Ledger Entry",
+				{"voucher_type": "Purchase Receipt", "voucher_no": pr.name, "is_cancelled": 0},
+			)
+		)
+		self.assertEqual(
+			frappe.db.get_value(
+				"Stock Ledger Entry",
+				{"voucher_type": "Purchase Receipt", "voucher_no": pr.name, "is_cancelled": 0},
+				"stock_value_difference",
+			),
+			100,
+		)
+
 	def test_landed_cost_voucher_against_purchase_invoice(self):
 
 		pi = make_purchase_invoice(
@@ -516,7 +569,7 @@
 
 	lcv = frappe.new_doc("Landed Cost Voucher")
 	lcv.company = args.company or "_Test Company"
-	lcv.distribute_charges_based_on = "Amount"
+	lcv.distribute_charges_based_on = args.distribute_charges_based_on or "Amount"
 
 	lcv.set(
 		"purchase_receipts",
diff --git a/erpnext/stock/doctype/material_request/material_request.js b/erpnext/stock/doctype/material_request/material_request.js
index 156e591..c1f1b0d 100644
--- a/erpnext/stock/doctype/material_request/material_request.js
+++ b/erpnext/stock/doctype/material_request/material_request.js
@@ -110,8 +110,11 @@
 
 				if (frm.doc.material_request_type === "Material Transfer") {
 					add_create_pick_list_button();
-					frm.add_custom_button(__("Transfer Material"),
+					frm.add_custom_button(__("Material Transfer"),
 						() => frm.events.make_stock_entry(frm), __('Create'));
+
+					frm.add_custom_button(__("Material Transfer (In Transit)"),
+						() => frm.events.make_in_transit_stock_entry(frm), __('Create'));
 				}
 
 				if (frm.doc.material_request_type === "Material Issue") {
@@ -333,6 +336,46 @@
 		});
 	},
 
+	make_in_transit_stock_entry(frm) {
+		frappe.prompt(
+			[
+				{
+					label: __('In Transit Warehouse'),
+					fieldname: 'in_transit_warehouse',
+					fieldtype: 'Link',
+					options: 'Warehouse',
+					reqd: 1,
+					get_query: () => {
+						return{
+							filters: {
+								'company': frm.doc.company,
+								'is_group': 0,
+								'warehouse_type': 'Transit'
+							}
+						}
+					}
+				}
+			],
+			(values) => {
+				frappe.call({
+					method: "erpnext.stock.doctype.material_request.material_request.make_in_transit_stock_entry",
+					args: {
+						source_name: frm.doc.name,
+						in_transit_warehouse: values.in_transit_warehouse
+					},
+					callback: function(r) {
+						if (r.message) {
+							let doc = frappe.model.sync(r.message);
+							frappe.set_route('Form', doc[0].doctype, doc[0].name);
+						}
+					}
+				})
+			},
+			__('In Transit Transfer'),
+			__("Create Stock Entry")
+		)
+	},
+
 	create_pick_list: (frm) => {
 		frappe.model.open_mapped_doc({
 			method: "erpnext.stock.doctype.material_request.material_request.create_pick_list",
diff --git a/erpnext/stock/doctype/material_request/material_request.py b/erpnext/stock/doctype/material_request/material_request.py
index 94f63a5..6426fe8 100644
--- a/erpnext/stock/doctype/material_request/material_request.py
+++ b/erpnext/stock/doctype/material_request/material_request.py
@@ -716,3 +716,14 @@
 	doc.set_item_locations()
 
 	return doc
+
+
+@frappe.whitelist()
+def make_in_transit_stock_entry(source_name, in_transit_warehouse):
+	ste_doc = make_stock_entry(source_name)
+	ste_doc.add_to_transit = 1
+
+	for row in ste_doc.items:
+		row.t_warehouse = in_transit_warehouse
+
+	return ste_doc
diff --git a/erpnext/stock/doctype/material_request/test_material_request.py b/erpnext/stock/doctype/material_request/test_material_request.py
index f0a9499..a707c74 100644
--- a/erpnext/stock/doctype/material_request/test_material_request.py
+++ b/erpnext/stock/doctype/material_request/test_material_request.py
@@ -11,6 +11,7 @@
 
 from erpnext.stock.doctype.item.test_item import create_item
 from erpnext.stock.doctype.material_request.material_request import (
+	make_in_transit_stock_entry,
 	make_purchase_order,
 	make_stock_entry,
 	make_supplier_quotation,
@@ -56,6 +57,22 @@
 		self.assertEqual(se.doctype, "Stock Entry")
 		self.assertEqual(len(se.get("items")), len(mr.get("items")))
 
+	def test_in_transit_make_stock_entry(self):
+		mr = frappe.copy_doc(test_records[0]).insert()
+
+		self.assertRaises(frappe.ValidationError, make_stock_entry, mr.name)
+
+		mr = frappe.get_doc("Material Request", mr.name)
+		mr.material_request_type = "Material Transfer"
+		mr.submit()
+
+		in_transit_warehouse = get_in_transit_warehouse(mr.company)
+		se = make_in_transit_stock_entry(mr.name, in_transit_warehouse)
+
+		self.assertEqual(se.doctype, "Stock Entry")
+		for row in se.get("items"):
+			self.assertEqual(row.t_warehouse, in_transit_warehouse)
+
 	def _insert_stock_entry(self, qty1, qty2, warehouse=None):
 		se = frappe.get_doc(
 			{
@@ -742,6 +759,36 @@
 		self.assertEqual(existing_requested_qty, current_requested_qty)
 
 
+def get_in_transit_warehouse(company):
+	if not frappe.db.exists("Warehouse Type", "Transit"):
+		frappe.get_doc(
+			{
+				"doctype": "Warehouse Type",
+				"name": "Transit",
+			}
+		).insert()
+
+	in_transit_warehouse = frappe.db.exists(
+		"Warehouse", {"warehouse_type": "Transit", "company": company}
+	)
+
+	if not in_transit_warehouse:
+		in_transit_warehouse = (
+			frappe.get_doc(
+				{
+					"doctype": "Warehouse",
+					"warehouse_name": "Transit",
+					"warehouse_type": "Transit",
+					"company": company,
+				}
+			)
+			.insert()
+			.name
+		)
+
+	return in_transit_warehouse
+
+
 def make_material_request(**args):
 	args = frappe._dict(args)
 	mr = frappe.new_doc("Material Request")
diff --git a/erpnext/stock/doctype/price_list/test_records.json b/erpnext/stock/doctype/price_list/test_records.json
index 7ca949c..e02a7ad 100644
--- a/erpnext/stock/doctype/price_list/test_records.json
+++ b/erpnext/stock/doctype/price_list/test_records.json
@@ -31,5 +31,21 @@
         "enabled": 1,
         "price_list_name": "_Test Price List Rest of the World",
         "selling": 1
+    },
+    {
+        "buying": 0,
+        "currency": "USD",
+        "doctype": "Price List",
+        "enabled": 1,
+        "price_list_name": "_Test Selling Price List",
+        "selling": 1
+    },
+    {
+        "buying": 1,
+        "currency": "USD",
+        "doctype": "Price List",
+        "enabled": 1,
+        "price_list_name": "_Test Buying Price List",
+        "selling": 0
     }
 ]
diff --git a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py
index af0d148..bb318f7 100644
--- a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py
+++ b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py
@@ -887,18 +887,10 @@
 
 	# Update Billing % based on pending accepted qty
 	total_amount, total_billed_amount = 0, 0
-	for item in pr_doc.items:
-		return_data = frappe.get_all(
-			"Purchase Receipt",
-			fields=["sum(abs(`tabPurchase Receipt Item`.qty)) as qty"],
-			filters=[
-				["Purchase Receipt", "docstatus", "=", 1],
-				["Purchase Receipt", "is_return", "=", 1],
-				["Purchase Receipt Item", "purchase_receipt_item", "=", item.name],
-			],
-		)
+	item_wise_returned_qty = get_item_wise_returned_qty(pr_doc)
 
-		returned_qty = return_data[0].qty if return_data else 0
+	for item in pr_doc.items:
+		returned_qty = flt(item_wise_returned_qty.get(item.name))
 		returned_amount = flt(returned_qty) * flt(item.rate)
 		pending_amount = flt(item.amount) - returned_amount
 		total_billable_amount = pending_amount if item.billed_amt <= pending_amount else item.billed_amt
@@ -915,6 +907,27 @@
 		pr_doc.notify_update()
 
 
+def get_item_wise_returned_qty(pr_doc):
+	items = [d.name for d in pr_doc.items]
+
+	return frappe._dict(
+		frappe.get_all(
+			"Purchase Receipt",
+			fields=[
+				"`tabPurchase Receipt Item`.purchase_receipt_item",
+				"sum(abs(`tabPurchase Receipt Item`.qty)) as qty",
+			],
+			filters=[
+				["Purchase Receipt", "docstatus", "=", 1],
+				["Purchase Receipt", "is_return", "=", 1],
+				["Purchase Receipt Item", "purchase_receipt_item", "in", items],
+			],
+			group_by="`tabPurchase Receipt Item`.purchase_receipt_item",
+			as_list=1,
+		)
+	)
+
+
 @frappe.whitelist()
 def make_purchase_invoice(source_name, target_doc=None):
 	from erpnext.accounts.party import get_payment_terms_template
@@ -1121,13 +1134,25 @@
 						account.expense_account, {"amount": 0.0, "base_amount": 0.0}
 					)
 
-					item_account_wise_cost[(item.item_code, item.purchase_receipt_item)][account.expense_account][
-						"amount"
-					] += (account.amount * item.get(based_on_field) / total_item_cost)
+					if total_item_cost > 0:
+						item_account_wise_cost[(item.item_code, item.purchase_receipt_item)][
+							account.expense_account
+						]["amount"] += (
+							account.amount * item.get(based_on_field) / total_item_cost
+						)
 
-					item_account_wise_cost[(item.item_code, item.purchase_receipt_item)][account.expense_account][
-						"base_amount"
-					] += (account.base_amount * item.get(based_on_field) / total_item_cost)
+						item_account_wise_cost[(item.item_code, item.purchase_receipt_item)][
+							account.expense_account
+						]["base_amount"] += (
+							account.base_amount * item.get(based_on_field) / total_item_cost
+						)
+					else:
+						item_account_wise_cost[(item.item_code, item.purchase_receipt_item)][
+							account.expense_account
+						]["amount"] += item.applicable_charges
+						item_account_wise_cost[(item.item_code, item.purchase_receipt_item)][
+							account.expense_account
+						]["base_amount"] += item.applicable_charges
 
 	return item_account_wise_cost
 
diff --git a/erpnext/stock/doctype/purchase_receipt_item/purchase_receipt_item.json b/erpnext/stock/doctype/purchase_receipt_item/purchase_receipt_item.json
index 557bb59..7a350b9 100644
--- a/erpnext/stock/doctype/purchase_receipt_item/purchase_receipt_item.json
+++ b/erpnext/stock/doctype/purchase_receipt_item/purchase_receipt_item.json
@@ -859,7 +859,8 @@
    "label": "Purchase Receipt Item",
    "no_copy": 1,
    "print_hide": 1,
-   "read_only": 1
+   "read_only": 1,
+   "search_index": 1
   },
   {
    "collapsible": 1,
@@ -974,7 +975,8 @@
    "label": "Purchase Invoice Item",
    "no_copy": 1,
    "print_hide": 1,
-   "read_only": 1
+   "read_only": 1,
+   "search_index": 1
   },
   {
    "fieldname": "product_bundle",
@@ -1010,7 +1012,7 @@
  "idx": 1,
  "istable": 1,
  "links": [],
- "modified": "2022-11-02 12:49:28.746701",
+ "modified": "2023-01-18 15:48:58.114923",
  "modified_by": "Administrator",
  "module": "Stock",
  "name": "Purchase Receipt Item",
diff --git a/erpnext/stock/doctype/stock_reposting_settings/stock_reposting_settings.js b/erpnext/stock/doctype/stock_reposting_settings/stock_reposting_settings.js
index 42d0723..5f81679 100644
--- a/erpnext/stock/doctype/stock_reposting_settings/stock_reposting_settings.js
+++ b/erpnext/stock/doctype/stock_reposting_settings/stock_reposting_settings.js
@@ -2,7 +2,22 @@
 // For license information, please see license.txt
 
 frappe.ui.form.on('Stock Reposting Settings', {
-	// refresh: function(frm) {
+	refresh: function(frm) {
+		frm.trigger('convert_to_item_based_reposting');
+	},
 
-	// }
+	convert_to_item_based_reposting: function(frm) {
+		frm.add_custom_button(__('Convert to Item Based Reposting'), function() {
+			frm.call({
+				method: 'convert_to_item_wh_reposting',
+				frezz: true,
+				doc: frm.doc,
+				callback: function(r) {
+					if (!r.exc) {
+						frm.reload_doc();
+					}
+				}
+			})
+		})
+	}
 });
diff --git a/erpnext/stock/doctype/stock_reposting_settings/stock_reposting_settings.py b/erpnext/stock/doctype/stock_reposting_settings/stock_reposting_settings.py
index e0c8ed1..51fb5ac 100644
--- a/erpnext/stock/doctype/stock_reposting_settings/stock_reposting_settings.py
+++ b/erpnext/stock/doctype/stock_reposting_settings/stock_reposting_settings.py
@@ -1,6 +1,8 @@
 # Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and contributors
 # For license information, please see license.txt
 
+import frappe
+from frappe import _
 from frappe.model.document import Document
 from frappe.utils import add_to_date, get_datetime, get_time_str, time_diff_in_hours
 
@@ -24,3 +26,62 @@
 
 		if diff < 10:
 			self.end_time = get_time_str(add_to_date(self.start_time, hours=10, as_datetime=True))
+
+	@frappe.whitelist()
+	def convert_to_item_wh_reposting(self):
+		"""Convert Transaction reposting to Item Warehouse based reposting if Item Based Reposting has enabled."""
+
+		reposting_data = get_reposting_entries()
+
+		vouchers = [d.voucher_no for d in reposting_data]
+
+		item_warehouses = {}
+
+		for ledger in get_stock_ledgers(vouchers):
+			key = (ledger.item_code, ledger.warehouse)
+			if key not in item_warehouses:
+				item_warehouses[key] = ledger.posting_date
+			elif frappe.utils.getdate(item_warehouses.get(key)) > frappe.utils.getdate(ledger.posting_date):
+				item_warehouses[key] = ledger.posting_date
+
+		for key, posting_date in item_warehouses.items():
+			item_code, warehouse = key
+			create_repost_item_valuation(item_code, warehouse, posting_date)
+
+		for row in reposting_data:
+			frappe.db.set_value("Repost Item Valuation", row.name, "status", "Skipped")
+
+		self.db_set("item_based_reposting", 1)
+		frappe.msgprint(_("Item Warehouse based reposting has been enabled."))
+
+
+def get_reposting_entries():
+	return frappe.get_all(
+		"Repost Item Valuation",
+		fields=["voucher_no", "name"],
+		filters={"status": ("in", ["Queued", "In Progress"]), "docstatus": 1, "based_on": "Transaction"},
+	)
+
+
+def get_stock_ledgers(vouchers):
+	return frappe.get_all(
+		"Stock Ledger Entry",
+		fields=["item_code", "warehouse", "posting_date"],
+		filters={"voucher_no": ("in", vouchers)},
+	)
+
+
+def create_repost_item_valuation(item_code, warehouse, posting_date):
+	frappe.get_doc(
+		{
+			"doctype": "Repost Item Valuation",
+			"company": frappe.get_cached_value("Warehouse", warehouse, "company"),
+			"posting_date": posting_date,
+			"based_on": "Item and Warehouse",
+			"posting_time": "00:00:01",
+			"item_code": item_code,
+			"warehouse": warehouse,
+			"allow_negative_stock": True,
+			"status": "Queued",
+		}
+	).submit()
diff --git a/erpnext/stock/get_item_details.py b/erpnext/stock/get_item_details.py
index 5af1441..b53f429 100644
--- a/erpnext/stock/get_item_details.py
+++ b/erpnext/stock/get_item_details.py
@@ -88,8 +88,15 @@
 
 	update_party_blanket_order(args, out)
 
+	# Never try to find a customer price if customer is set in these Doctype
+	current_customer = args.customer
+	if args.get("doctype") in ["Purchase Order", "Purchase Receipt", "Purchase Invoice"]:
+		args.customer = None
+
 	out.update(get_price_list_rate(args, item))
 
+	args.customer = current_customer
+
 	if args.customer and cint(args.is_pos):
 		out.update(get_pos_profile_item_details(args.company, args, update_data=True))
 
diff --git a/erpnext/stock/report/stock_ledger/stock_ledger.py b/erpnext/stock/report/stock_ledger/stock_ledger.py
index 8b63c0f..da17cde 100644
--- a/erpnext/stock/report/stock_ledger/stock_ledger.py
+++ b/erpnext/stock/report/stock_ledger/stock_ledger.py
@@ -306,7 +306,7 @@
 		query = query.where(sle.item_code.isin(items))
 
 	for field in ["voucher_no", "batch_no", "project", "company"]:
-		if filters.get(field):
+		if filters.get(field) and field not in inventory_dimension_fields:
 			query = query.where(sle[field] == filters.get(field))
 
 	query = apply_warehouse_filter(query, sle, filters)
diff --git a/erpnext/stock/stock_balance.py b/erpnext/stock/stock_balance.py
index 14cedd2..439ed7a 100644
--- a/erpnext/stock/stock_balance.py
+++ b/erpnext/stock/stock_balance.py
@@ -121,7 +121,7 @@
 					and parenttype='Sales Order'
 					and item_code != parent_item
 					and exists (select * from `tabSales Order` so
-					where name = dnpi_in.parent and docstatus = 1 and status != 'Closed')
+					where name = dnpi_in.parent and docstatus = 1 and status not in ('On Hold', 'Closed'))
 				) dnpi)
 			union
 				(select stock_qty as dnpi_qty, qty as so_item_qty,
@@ -131,7 +131,7 @@
 				and (so_item.delivered_by_supplier is null or so_item.delivered_by_supplier = 0)
 				and exists(select * from `tabSales Order` so
 					where so.name = so_item.parent and so.docstatus = 1
-					and so.status != 'Closed'))
+					and so.status not in ('On Hold', 'Closed')))
 			) tab
 		where
 			so_item_qty >= so_item_delivered_qty
diff --git a/erpnext/stock/tests/test_get_item_details.py b/erpnext/stock/tests/test_get_item_details.py
new file mode 100644
index 0000000..b53e29e
--- /dev/null
+++ b/erpnext/stock/tests/test_get_item_details.py
@@ -0,0 +1,40 @@
+import json
+
+import frappe
+from frappe.test_runner import make_test_records
+from frappe.tests.utils import FrappeTestCase
+
+from erpnext.stock.get_item_details import get_item_details
+
+test_ignore = ["BOM"]
+test_dependencies = ["Customer", "Supplier", "Item", "Price List", "Item Price"]
+
+
+class TestGetItemDetail(FrappeTestCase):
+	def setUp(self):
+		make_test_records("Price List")
+		super().setUp()
+
+	def test_get_item_detail_purchase_order(self):
+
+		args = frappe._dict(
+			{
+				"item_code": "_Test Item",
+				"company": "_Test Company",
+				"customer": "_Test Customer",
+				"conversion_rate": 1.0,
+				"price_list_currency": "USD",
+				"plc_conversion_rate": 1.0,
+				"doctype": "Purchase Order",
+				"name": None,
+				"supplier": "_Test Supplier",
+				"transaction_date": None,
+				"conversion_rate": 1.0,
+				"price_list": "_Test Buying Price List",
+				"is_subcontracted": 0,
+				"ignore_pricing_rule": 1,
+				"qty": 1,
+			}
+		)
+		details = get_item_details(args)
+		self.assertEqual(details.get("price_list_rate"), 100)
diff --git a/erpnext/subcontracting/doctype/subcontracting_order/test_subcontracting_order.py b/erpnext/subcontracting/doctype/subcontracting_order/test_subcontracting_order.py
index d054ce0..6a2983f 100644
--- a/erpnext/subcontracting/doctype/subcontracting_order/test_subcontracting_order.py
+++ b/erpnext/subcontracting/doctype/subcontracting_order/test_subcontracting_order.py
@@ -2,6 +2,7 @@
 # See license.txt
 
 import copy
+from collections import defaultdict
 
 import frappe
 from frappe.tests.utils import FrappeTestCase
@@ -186,6 +187,40 @@
 		)
 		self.assertEqual(len(ste.items), len(rm_items))
 
+	def test_make_rm_stock_entry_for_batch_items_with_less_transfer(self):
+		set_backflush_based_on("BOM")
+
+		service_items = [
+			{
+				"warehouse": "_Test Warehouse - _TC",
+				"item_code": "Subcontracted Service Item 4",
+				"qty": 5,
+				"rate": 100,
+				"fg_item": "Subcontracted Item SA4",
+				"fg_item_qty": 5,
+			}
+		]
+
+		sco = get_subcontracting_order(service_items=service_items)
+		rm_items = get_rm_items(sco.supplied_items)
+		itemwise_details = make_stock_in_entry(rm_items=rm_items)
+
+		itemwise_transfer_qty = defaultdict(int)
+		for item in rm_items:
+			item["qty"] -= 1
+			itemwise_transfer_qty[item["item_code"]] += item["qty"]
+
+		ste = make_stock_transfer_entry(
+			sco_no=sco.name,
+			rm_items=rm_items,
+			itemwise_details=copy.deepcopy(itemwise_details),
+		)
+
+		scr = make_subcontracting_receipt(sco.name)
+
+		for row in scr.supplied_items:
+			self.assertEqual(row.consumed_qty, itemwise_transfer_qty.get(row.rm_item_code) + 1)
+
 	def test_update_reserved_qty_for_subcontracting(self):
 		# Create RM Material Receipt
 		make_stock_entry(target="_Test Warehouse - _TC", item_code="_Test Item", qty=10, basic_rate=100)
diff --git a/erpnext/subcontracting/doctype/subcontracting_receipt/subcontracting_receipt.js b/erpnext/subcontracting/doctype/subcontracting_receipt/subcontracting_receipt.js
index b6bef8c..3a2c53f 100644
--- a/erpnext/subcontracting/doctype/subcontracting_receipt/subcontracting_receipt.js
+++ b/erpnext/subcontracting/doctype/subcontracting_receipt/subcontracting_receipt.js
@@ -51,13 +51,31 @@
 			}
 		}));
 
-		frm.set_query("expense_account", "items", function () {
+		frm.set_query('expense_account', 'items', function () {
 			return {
-				query: "erpnext.controllers.queries.get_expense_account",
+				query: 'erpnext.controllers.queries.get_expense_account',
 				filters: { 'company': frm.doc.company }
 			};
 		});
 
+		frm.set_query('batch_no', 'items', function(doc, cdt, cdn) {
+			var row = locals[cdt][cdn];
+			return {
+				filters: {
+					item: row.item_code
+				}
+			}
+		});
+
+		let batch_no_field = frm.get_docfield("items", "batch_no");
+		if (batch_no_field) {
+			batch_no_field.get_route_options_for_new_doc = function(row) {
+				return {
+					"item": row.doc.item_code
+				}
+			};
+		}
+
 		frappe.db.get_single_value('Buying Settings', 'backflush_raw_materials_of_subcontract_based_on').then(val => {
 			if (val == 'Material Transferred for Subcontract') {
 				frm.fields_dict['supplied_items'].grid.grid_rows.forEach((grid_row) => {
@@ -73,7 +91,7 @@
 
 	refresh: (frm) => {
 		if (frm.doc.docstatus > 0) {
-			frm.add_custom_button(__("Stock Ledger"), function () {
+			frm.add_custom_button(__('Stock Ledger'), function () {
 				frappe.route_options = {
 					voucher_no: frm.doc.name,
 					from_date: frm.doc.posting_date,
@@ -81,8 +99,8 @@
 					company: frm.doc.company,
 					show_cancelled_entries: frm.doc.docstatus === 2
 				};
-				frappe.set_route("query-report", "Stock Ledger");
-			}, __("View"));
+				frappe.set_route('query-report', 'Stock Ledger');
+			}, __('View'));
 
 			frm.add_custom_button(__('Accounting Ledger'), function () {
 				frappe.route_options = {
@@ -90,11 +108,11 @@
 					from_date: frm.doc.posting_date,
 					to_date: moment(frm.doc.modified).format('YYYY-MM-DD'),
 					company: frm.doc.company,
-					group_by: "Group by Voucher (Consolidated)",
+					group_by: 'Group by Voucher (Consolidated)',
 					show_cancelled_entries: frm.doc.docstatus === 2
 				};
-				frappe.set_route("query-report", "General Ledger");
-			}, __("View"));
+				frappe.set_route('query-report', 'General Ledger');
+			}, __('View'));
 		}
 
 		if (!frm.doc.is_return && frm.doc.docstatus == 1 && frm.doc.per_returned < 100) {
@@ -111,25 +129,25 @@
 			frm.add_custom_button(__('Subcontracting Order'), function () {
 				if (!frm.doc.supplier) {
 					frappe.throw({
-						title: __("Mandatory"),
-						message: __("Please Select a Supplier")
+						title: __('Mandatory'),
+						message: __('Please Select a Supplier')
 					});
 				}
 
 				erpnext.utils.map_current_doc({
 					method: 'erpnext.subcontracting.doctype.subcontracting_order.subcontracting_order.make_subcontracting_receipt',
-					source_doctype: "Subcontracting Order",
+					source_doctype: 'Subcontracting Order',
 					target: frm,
 					setters: {
 						supplier: frm.doc.supplier,
 					},
 					get_query_filters: {
 						docstatus: 1,
-						per_received: ["<", 100],
+						per_received: ['<', 100],
 						company: frm.doc.company
 					}
 				});
-			}, __("Get Items From"));
+			}, __('Get Items From'));
 		}
 	},
 
diff --git a/erpnext/templates/pages/order.html b/erpnext/templates/pages/order.html
index 6b354b2..bc34ad5 100644
--- a/erpnext/templates/pages/order.html
+++ b/erpnext/templates/pages/order.html
@@ -34,16 +34,18 @@
 				</a>
 			</ul>
 		</div>
-		<div class="form-column col-sm-6">
-			<div class="page-header-actions-block" data-html-block="header-actions">
-				<p>
-					<a href="/api/method/erpnext.accounts.doctype.payment_request.payment_request.make_payment_request?dn={{ doc.name }}&dt={{ doc.doctype }}&submit_doc=1&order_type=Shopping Cart"
-						class="btn btn-primary btn-sm" id="pay-for-order">
-						{{ _("Pay") }} {{doc.get_formatted("grand_total") }}
-					</a>
-				</p>
+		{% if show_pay_button %}
+			<div class="form-column col-sm-6">
+				<div class="page-header-actions-block" data-html-block="header-actions">
+					<p>
+						<a href="/api/method/erpnext.accounts.doctype.payment_request.payment_request.make_payment_request?dn={{ doc.name }}&dt={{ doc.doctype }}&submit_doc=1&order_type=Shopping Cart"
+							class="btn btn-primary btn-sm" id="pay-for-order">
+							{{ _("Pay") }} {{doc.get_formatted("grand_total") }}
+						</a>
+					</p>
+				</div>
 			</div>
-		</div>
+		{% endif %}
 	</div>
 {% endblock %}
 
diff --git a/erpnext/templates/pages/order.py b/erpnext/templates/pages/order.py
index 185ec66..13772d3 100644
--- a/erpnext/templates/pages/order.py
+++ b/erpnext/templates/pages/order.py
@@ -55,6 +55,7 @@
 			)
 			context.available_loyalty_points = int(loyalty_program_details.get("loyalty_points"))
 
+	context.show_pay_button = frappe.db.get_single_value("Buying Settings", "show_pay_button")
 	context.show_make_pi_button = False
 	if context.doc.get("supplier"):
 		# show Make Purchase Invoice button based on permission
diff --git a/pyproject.toml b/pyproject.toml
index 1b342a5..1c93eed 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -10,8 +10,8 @@
 dependencies = [
     # Core dependencies
     "pycountry~=20.7.3",
-    "python-stdnum~=1.16",
     "Unidecode~=1.2.0",
+    "barcodenumber~=0.5.0",
 
     # integration dependencies
     "gocardless-pro~=1.22.0",